Blame it on Caesar!

A presentation by
Lennart Regebro

Lunar calendars:

The year is twelve lunar months long.

The year is out of sync with the seasons.

Examples: The Islamic calendar

Lunisolar calendars:

The year is twelve or thirteen lunar months long.

The year is kept in sync with the seasons by leap months.

Examples: The Hebrew, Buddhist, Burmese, Babylonian, etc, etc...

Solar calendars:

The year follows the solstices/seasons.

The moon is ignored completely.

Examples: The French republican calendar, the Julian Calendar, the Ancient Egyptian calendar
and it's descendants.

My calendar is better than yours!

   def day_of_year(month, day):
       return (month - 1) * 30 + day_of_month

   def day_of_week(day):
      return ((day - 1) % 10) + 1 

   def weekno(month, day):
      return ((day_of_year(month, day) - 1) // 10) + 1
        
MONTH_LENGHTS_STD = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
MONTH_LENGHTS_LYR = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
MONTH_DAY_OF_WEEK = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]
   
def day_of_year(year, month, day):
    if not year % 4 and year % 100 or not year % 400:
        d = MONTH_LENGHTS_LYR[month-1]
    else:
        d = MONTH_LENGHTS_STD[month-1]
    return d + day

 def day_of_week(year, month, day):
    if month < 3:
        year -= 1
    dow = (year + year//4 - year//100 + year//400 + 
           MONTH_DAY_OF_WEEK[month-1] + day) % 7
    if dow == 0:
        dow = 7
    return dow

def _weekno(year, month, day):
    return (day_of_year(year, month, day) - 
            day_of_week(year, month, day) + 10) // 7
    
def weekno(year, month, day):
    week = _weekno(year, month, day)
    if week == 0:
        week = _weekno(year - 1, 12, 31)
    if week == 53:
        if _weekno(year + 1, 1, 1) == 1:
            week = 1
    return week

momentjs.com

http://www.date4j.net/

BST: 5 different zones

CST: 4 different zones

IST: 4 different zones

America/Chicago

Australia/Canberra

Asia/Shanghai

Asia/Taipei

>>> from datetime import date
>>> date(2011,  2, 29)
Traceback (most recent call last):
  File "", line 1, in 
ValueError: day is out of range for month
js> new Date(2011, 1, 29);
Tue Mar 01 2011 00:00:00 GMT+0100 (CET)
js> y = 2011; m = 1; d = 29;
js> dt = new Date(y, m, d);
js> if (dt.getFullYear() !== y || 
        dt.getMonth() !== m || 
        dt.getDay() !== d) {
  > (Insert error handling here)
  > }
$ TZ='Europe/Rome' js
Rhino 1.7 release 3 2012 02 16
js> new Date(1972, 4, 28);
Sat May 27 1972 23:00:00 GMT+0100 (CET)
js> new Date(y, m, d, 3);
Sun May 28 1972 03:00:00 GMT+0200 (CEST)

Python & Timezones

pytz 15 - 0 dateutil

pytz 15 - 15 dateutil

pytz 30 - 15 dateutil

pytz 30 - 30 dateutil

Which half past three do you mean?

>>> rome = pytz.timezone('Europe/Rome')
>>> rome.localize(datetime(1972, 5, 28, 0, 0), is_dst=None)
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib/python2.7/dist-packages/pytz/tzinfo.py",
    line 322, in localize
    raise NonExistentTimeError(dt)
pytz.exceptions.NonExistentTimeError: 1972-05-28 00:00:00
>>> 

pytz 40 - 30 dateutil

pytz 40 - 40 dateutil

http://pypi.python.org/pypi/tzlocal

Advantage pytz

Parsing timezones

>>> from dateutil.parser import parse
        
>>> parse('2003-09-25 12:45 -0300')
datetime.datetime(2003, 9, 25, 12, 45, 
        tzinfo=tzoffset(None, -10800))
        
>>> parse('2003-09-25 12:45 GMT-0300')
datetime.datetime(2003, 9, 25, 12, 45, 
        tzinfo=tzoffset(None, 10800))

RFC 5545 aka iCalendar

RFC 2445 is obsolete

+----------+--------+--------+-------+-------+------+-------+------+
|          |SECONDLY|MINUTELY|HOURLY |DAILY  |WEEKLY|MONTHLY|YEARLY|
+----------+--------+--------+-------+-------+------+-------+------+
|BYMONTH   |Limit   |Limit   |Limit  |Limit  |Limit |Limit  |Expand|
+----------+--------+--------+-------+-------+------+-------+------+
|BYWEEKNO  |N/A     |N/A     |N/A    |N/A    |N/A   |N/A    |Expand|
+----------+--------+--------+-------+-------+------+-------+------+
|BYYEARDAY |Limit   |Limit   |Limit  |N/A    |N/A   |N/A    |Expand|
+----------+--------+--------+-------+-------+------+-------+------+
|BYMONTHDAY|Limit   |Limit   |Limit  |Limit  |N/A   |Expand |Expand|
+----------+--------+--------+-------+-------+------+-------+------+
|BYDAY     |Limit   |Limit   |Limit  |Limit  |Expand|Note 1 |Note 2|
+----------+--------+--------+-------+-------+------+-------+------+
|BYHOUR    |Limit   |Limit   |Limit  |Expand |Expand|Expand |Expand|
+----------+--------+--------+-------+-------+------+-------+------+
|BYMINUTE  |Limit   |Limit   |Expand |Expand |Expand|Expand |Expand|
+----------+--------+--------+-------+-------+------+-------+------+
|BYSECOND  |Limit   |Expand  |Expand |Expand |Expand|Expand |Expand|
+----------+--------+--------+-------+-------+------+-------+------+
|BYSETPOS  |Limit   |Limit   |Limit  |Limit  |Limit |Limit  |Limit |
+----------+--------+--------+-------+-------+------+-------+------+

dateutil.easter

dateutil.rrule

DTSTART;TZID=America/New_York:19980119T020000
DTSTART:19980119T080000Z
DTSTART:19980119T020000

http://pypi.python.org/pypi/icalendar

- Mixing timezoned and timezone-naive events?

- Conferences on boats?

- End-date or duration?

https://github.com/collective/jquery.recurrenceinput.js

http://regebro.wordpress.com/