Revision: 4584
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4584&view=rev
Author: jswhit
Date: 2007-12-04 11:18:03 -0800 (Tue, 04 Dec 2007)
Log Message:
-----------
move netcdftime.py
Modified Paths:
--------------
trunk/toolkits/basemap/MANIFEST.in
trunk/toolkits/basemap/examples/fcstmaps.py
trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/basemap.py
trunk/toolkits/basemap/setup.py
Added Paths:
-----------
trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/netcdftime.py
Modified: trunk/toolkits/basemap/MANIFEST.in
===================================================================
--- trunk/toolkits/basemap/MANIFEST.in 2007-12-04 19:16:57 UTC (rev 4583)
+++ trunk/toolkits/basemap/MANIFEST.in 2007-12-04 19:18:03 UTC (rev 4584)
@@ -68,6 +68,7 @@
include lib/matplotlib/toolkits/basemap/pyproj.py
include lib/matplotlib/toolkits/basemap/cm.py
include lib/matplotlib/toolkits/basemap/pupynere.py
+include lib/matplotlib/toolkits/basemap/netcdftime.py
include pyshapelib/README pyshapelib/COPYING pyshapelib/ChangeLog
pyshapelib/NEWS
include pyshapelib/*.i pyshapelib/*.c pyshapelib/*.py pyshapelib/*.h
include pyshapelib/*.shp pyshapelib/*.shx pyshapelib/*.dbf
@@ -78,7 +79,6 @@
recursive-include lib/httplib2 *
recursive-include lib/dbflib *
recursive-include lib/shapelib *
-recursive-include lib/netcdftime *
include lib/matplotlib/toolkits/basemap/data/5minmask.bin
include lib/matplotlib/toolkits/basemap/data/GL27
include lib/matplotlib/toolkits/basemap/data/countries_c.dat
Modified: trunk/toolkits/basemap/examples/fcstmaps.py
===================================================================
--- trunk/toolkits/basemap/examples/fcstmaps.py 2007-12-04 19:16:57 UTC (rev
4583)
+++ trunk/toolkits/basemap/examples/fcstmaps.py 2007-12-04 19:18:03 UTC (rev
4584)
@@ -36,9 +36,6 @@
longitudes = data.variables['lon']
fcsttimes = data.variables['time']
times = fcsttimes[0:6] # first 6 forecast times.
-# change 0.0 to 00 at end of time units string
-# (so strptime will understand it).
-timeunits = fcsttimes.units[:-2]+'0'
ntimes = len(times)
# put forecast times in YYYYMMDDHH format.
verifdates = []
@@ -46,7 +43,7 @@
for time in times:
print time, times[0]
fcsthrs.append(int((time-times[0])*24))
- fdate = num2date(time,'days since 0001-01-01 00:00:00')
+ fdate = num2date(time,fcsttimes.units)
verifdates.append(fdate.strftime('%Y%m%d%H'))
print fcsthrs
print verifdates
Modified: trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/basemap.py
===================================================================
--- trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/basemap.py
2007-12-04 19:16:57 UTC (rev 4583)
+++ trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/basemap.py
2007-12-04 19:18:03 UTC (rev 4584)
@@ -2858,28 +2858,21 @@
f = pupynere._LocalFile(file,maskandscale)
return f
-def num2date(times,units,unit_format='%Y-%m-%d %H:%M:%S',calendar='standard'):
+def num2date(times,units,calendar='standard'):
"""
Return datetime objects given numeric time values. The units
of the numeric time values are described by the units argument
- and the unit_format and calendar keywords.
+ and the calendar keyword.
Arguments:
times - numeric time values. Maximum resolution is 1 second.
+
units - a string of the form '<time-units> since <reference time>'
describing the time units. <time-units> can be days, hours, minutes
- or seconds. <reference-time> is the time origin, defined by the format
- keyword (see below). For example, a valid choice would be
- units='hours since 0001-01-01 00:00:00'.
+ or seconds. <reference-time> is the time origin. A valid choice
+ would be units='hours since 0001-01-01 00:00:00'.
- Keyword Arguments:
-
- format - a string describing a reference time. This string is converted
- to a year,month,day,hour,minute,second tuple by strptime. The default
- format is '%Y-%m-%d %H:%M:%S'. See the time.strptime docstring for other
- valid formats.
-
calendar - describes the calendar used in the time calculations.
All the values currently defined in the CF metadata convention
(http://cf-pcmdi.llnl.gov/documents/cf-conventions/) are supported.
@@ -2897,31 +2890,24 @@
the weird dates in some calendars (such as '360_day' and 'all_leap'
which don't exist in any real world calendar.
"""
- cdftime = netcdftime.utime(units,calendar=calendar,format=unit_format)
+ cdftime = netcdftime.utime(units,calendar=calendar)
return cdftime.num2date(times)
-def date2num(dates,units,unit_format='%Y-%m-%d %H:%M:%S',calendar='standard'):
+def date2num(dates,units,calendar='standard'):
"""
Return numeric time values given datetime objects. The units
of the numeric time values are described by the units argument
- and the unit_format and calendar keywords.
+ and the calendar keyword.
Arguments:
dates - A datetime object or a sequence of datetime objects.
+
units - a string of the form '<time-units> since <reference time>'
describing the time units. <time-units> can be days, hours, minutes
- or seconds. <reference-time> is the time origin, defined by the format
- keyword (see below). For example, a valid choice would be
- units='hours since 0001-01-01 00:00:00'.
+ or seconds. <reference-time> is the time origin. A valid choice
+ would be units='hours since 0001-01-01 00:00:00'.
- Keyword Arguments:
-
- format - a string describing a reference time. This string is converted
- to a year,month,day,hour,minute,second tuple by strptime. The default
- format is '%Y-%m-%d %H:%M:%S'. See the time.strptime docstring for other
- valid formats.
-
calendar - describes the calendar used in the time calculations.
All the values currently defined in the CF metadata convention
(http://cf-pcmdi.llnl.gov/documents/cf-conventions/) are supported.
@@ -2932,5 +2918,5 @@
The maximum resolution of the numeric time values is 1 second.
"""
- cdftime = netcdftime.utime(units,calendar=calendar,format=unit_format)
+ cdftime = netcdftime.utime(units,calendar=calendar)
return cdftime.date2num(dates)
Added: trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/netcdftime.py
===================================================================
--- trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/netcdftime.py
(rev 0)
+++ trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/netcdftime.py
2007-12-04 19:18:03 UTC (rev 4584)
@@ -0,0 +1,859 @@
+"""
+Performs conversions of netCDF time coordinate data to/from datetime objects.
+"""
+import math, numpy, re, time
+from datetime import datetime as real_datetime
+
+_units = ['days','hours','minutes','seconds','day','hour','minute','second']
+_calendars =
['standard','gregorian','proleptic_gregorian','noleap','julian','all_leap','365_day','366_day','360_day']
+
+__version__ = '0.6'
+
+class datetime:
+ """
+Phony datetime object which mimics the python datetime object,
+but allows for dates that don't exist in the proleptic gregorian calendar.
+Doesn't do timedelta operations, doesn't overload + and -.
+
+Has strftime, timetuple and __repr__ methods. The format
+of the string produced by __repr__ is controlled by self.format
+(default %Y-%m-%d %H:%M:%S).
+
+Instance variables are year,month,day,hour,minute,second,dayofwk,dayofyr
+and format.
+ """
+ def
__init__(self,year,month,day,hour=0,minute=0,second=0,dayofwk=-1,dayofyr=1):
+ """dayofyr set to 1 by default - otherwise time.strftime will
complain"""
+ self.year=year
+ self.month=month
+ self.day=day
+ self.hour=hour
+ self.minute=minute
+ self.dayofwk=dayofwk
+ self.dayofyr=dayofyr
+ self.second=second
+ self.format='%Y-%m-%d %H:%M:%S'
+ def strftime(self,format=None):
+ if format is None:
+ format = self.format
+ return _strftime(self,format)
+ def timetuple(self):
+ return
(self.year,self.month,self.day,self.hour,self.minute,self.second,self.dayofwk,self.dayofyr,-1)
+ def __repr__(self):
+ return self.strftime(self.format)
+
+def JulianDayFromDate(date,calendar='standard'):
+
+ """
+
+creates a Julian Day from a 'datetime-like' object. Returns the fractional
+Julian Day (resolution 1 second).
+
+if calendar='standard' or 'gregorian' (default), Julian day follows Julian
+Calendar on and before 1582-10-5, Gregorian calendar after 1582-10-15.
+
+if calendar='proleptic_gregorian', Julian Day follows gregorian calendar.
+
+if calendar='julian', Julian Day follows julian calendar.
+
+Algorithm:
+
+Meeus, Jean (1998) Astronomical Algorithms (2nd Edition). Willmann-Bell,
+Virginia. p. 63
+
+ """
+
+ # based on redate.py by David Finlayson.
+
+ year=date.year; month=date.month; day=date.day
+ hour=date.hour; minute=date.minute; second=date.second
+ # Convert time to fractions of a day
+ day = day + hour/24.0 + minute/1440.0 + second/86400.0
+
+ # Start Meeus algorithm (variables are in his notation)
+ if (month < 3):
+ month = month + 12
+ year = year - 1
+
+ A = int(year/100)
+
+ jd = int(365.25 * (year + 4716)) + int(30.6001 * (month + 1)) + \
+ day - 1524.5
+
+ # optionally adjust the jd for the switch from
+ # the Julian to Gregorian Calendar
+ # here assumed to have occurred the day after 1582 October 4
+ if calendar in ['standard','gregorian']:
+ if jd >= 2299170.5:
+ # 1582 October 15 (Gregorian Calendar)
+ B = 2 - A + int(A/4)
+ elif jd < 2299160.5:
+ # 1582 October 5 (Julian Calendar)
+ B = 0
+ else:
+ raise ValueError, 'impossible date (falls in gap between end of
Julian calendar and beginning of Gregorian calendar'
+ elif calendar == 'proleptic_gregorian':
+ B = 2 - A + int(A/4)
+ elif calendar == 'julian':
+ B = 0
+ else:
+ raise ValueError, 'unknown calendar, must be one of
julian,standard,gregorian,proleptic_gregorian, got %s' % calendar
+
+ # adjust for Julian calendar if necessary
+ jd = jd + B
+
+ return jd
+
+def _NoLeapDayFromDate(date):
+
+ """
+
+creates a Julian Day for a calendar with no leap years from a datetime
+instance. Returns the fractional Julian Day (resolution 1 second).
+
+ """
+
+ year=date.year; month=date.month; day=date.day
+ hour=date.hour; minute=date.minute; second=date.second
+ # Convert time to fractions of a day
+ day = day + hour/24.0 + minute/1440.0 + second/86400.0
+
+ # Start Meeus algorithm (variables are in his notation)
+ if (month < 3):
+ month = month + 12
+ year = year - 1
+
+ jd = int(365. * (year + 4716)) + int(30.6001 * (month + 1)) + \
+ day - 1524.5
+
+ return jd
+
+def _AllLeapFromDate(date):
+
+ """
+
+creates a Julian Day for a calendar where all years have 366 days from
+a 'datetime-like' object.
+Returns the fractional Julian Day (resolution 1 second).
+
+ """
+
+ year=date.year; month=date.month; day=date.day
+ hour=date.hour; minute=date.minute; second=date.second
+ # Convert time to fractions of a day
+ day = day + hour/24.0 + minute/1440.0 + second/86400.0
+
+ # Start Meeus algorithm (variables are in his notation)
+ if (month < 3):
+ month = month + 12
+ year = year - 1
+
+ jd = int(366. * (year + 4716)) + int(30.6001 * (month + 1)) + \
+ day - 1524.5
+
+ return jd
+
+def _360DayFromDate(date):
+
+ """
+
+creates a Julian Day for a calendar where all months have 30 daysfrom
+a 'datetime-like' object.
+Returns the fractional Julian Day (resolution 1 second).
+
+ """
+
+ year=date.year; month=date.month; day=date.day
+ hour=date.hour; minute=date.minute; second=date.second
+ # Convert time to fractions of a day
+ day = day + hour/24.0 + minute/1440.0 + second/86400.0
+
+ jd = int(360. * (year + 4716)) + int(30. * (month - 1)) + day
+
+ return jd
+
+def DateFromJulianDay(JD,calendar='standard'):
+ """
+
+returns a 'datetime-like' object given Julian Day. Julian Day is a
+fractional day with a resolution of 1 second.
+
+if calendar='standard' or 'gregorian' (default), Julian day follows Julian
+Calendar on and before 1582-10-5, Gregorian calendar after 1582-10-15.
+
+if calendar='proleptic_gregorian', Julian Day follows gregorian calendar.
+
+if calendar='julian', Julian Day follows julian calendar.
+
+The datetime object is a 'real' datetime object if the date falls in
+the Gregorian calendar (i.e. calendar='proleptic_gregorian', or
+calendar = 'standard'/'gregorian' and the date is after 1582-10-15).
+Otherwise, it's a 'phony' datetime object which is actually an instance
+of netcdftime.datetime.
+
+
+Algorithm:
+
+Meeus, Jean (1998) Astronomical Algorithms (2nd Edition). Willmann-Bell,
+Virginia. p. 63
+
+ """
+
+ # based on redate.py by David Finlayson.
+
+ if JD < 0:
+ raise ValueError, 'Julian Day must be positive'
+
+ dayofwk = int(math.fmod(int(JD + 1.5),7))
+ (F, Z) = math.modf(JD + 0.5)
+ Z = int(Z)
+ if calendar in ['standard','gregorian']:
+ if JD < 2299160.5:
+ A = Z
+ else:
+ alpha = int((Z - 1867216.25)/36524.25)
+ A = Z + 1 + alpha - int(alpha/4)
+
+ elif calendar == 'proleptic_gregorian':
+ alpha = int((Z - 1867216.25)/36524.25)
+ A = Z + 1 + alpha - int(alpha/4)
+ elif calendar == 'julian':
+ A = Z
+ else:
+ raise ValueError, 'unknown calendar, must be one of
julian,standard,gregorian,proleptic_gregorian, got %s' % calendar
+
+ B = A + 1524
+ C = int((B - 122.1)/365.25)
+ D = int(365.25 * C)
+ E = int((B - D)/30.6001)
+
+ # Convert to date
+ day = B - D - int(30.6001 * E) + F
+ nday = B-D-123
+ if nday <= 305:
+ dayofyr = nday+60
+ else:
+ dayofyr = nday-305
+ if E < 14:
+ month = E - 1
+ else:
+ month = E - 13
+
+ if month > 2:
+ year = C - 4716
+ else:
+ year = C - 4715
+
+ # a leap year?
+ leap = 0
+ if year % 4 == 0:
+ leap = 1
+ if calendar == 'proleptic_gregorian' or \
+ (calendar in ['standard','gregorian'] and JD >= 2299160.5):
+ if year % 100 == 0 and year % 400 != 0:
+ print year % 100, year % 400
+ leap = 0
+ if leap and month > 2:
+ dayofyr = dayofyr + leap
+
+ # Convert fractions of a day to time
+ (dfrac, days) = math.modf(day/1.0)
+ (hfrac, hours) = math.modf(dfrac * 24.0)
+ (mfrac, minutes) = math.modf(hfrac * 60.0)
+ seconds = round(mfrac * 60.0) # seconds are rounded
+
+ if seconds > 59:
+ seconds = 0
+ minutes = minutes + 1
+ if minutes > 59:
+ minutes = 0
+ hours = hours + 1
+ if hours > 23:
+ hours = 0
+ days = days + 1
+
+ # return a 'real' datetime instance if calendar is gregorian.
+ if calendar == 'proleptic_gregorian' or \
+ (calendar in ['standard','gregorian'] and JD >= 2299160.5):
+ return
real_datetime(year,month,int(days),int(hours),int(minutes),int(seconds))
+ else:
+ # or else, return a 'datetime-like' instance.
+ return
datetime(year,month,int(days),int(hours),int(minutes),int(seconds),dayofwk,dayofyr)
+
+def _DateFromNoLeapDay(JD):
+ """
+
+returns a 'datetime-like' object given Julian Day for a calendar with no leap
+days. Julian Day is a fractional day with a resolution of 1 second.
+
+ """
+
+ # based on redate.py by David Finlayson.
+
+ if JD < 0:
+ raise ValueError, 'Julian Day must be positive'
+
+ dayofwk = int(math.fmod(int(JD + 1.5),7))
+ (F, Z) = math.modf(JD + 0.5)
+ Z = int(Z)
+ A = Z
+ B = A + 1524
+ C = int((B - 122.1)/365.)
+ D = int(365. * C)
+ E = int((B - D)/30.6001)
+
+ # Convert to date
+ day = B - D - int(30.6001 * E) + F
+ nday = B-D-123
+ if nday <= 305:
+ dayofyr = nday+60
+ else:
+ dayofyr = nday-305
+ if E < 14:
+ month = E - 1
+ else:
+ month = E - 13
+
+ if month > 2:
+ year = C - 4716
+ else:
+ year = C - 4715
+
+ # Convert fractions of a day to time
+ (dfrac, days) = math.modf(day/1.0)
+ (hfrac, hours) = math.modf(dfrac * 24.0)
+ (mfrac, minutes) = math.modf(hfrac * 60.0)
+ seconds = round(mfrac * 60.0) # seconds are rounded
+
+ if seconds > 59:
+ seconds = 0
+ minutes = minutes + 1
+ if minutes > 59:
+ minutes = 0
+ hours = hours + 1
+ if hours > 23:
+ hours = 0
+ days = days + 1
+
+ return datetime(year,month,int(days),int(hours),int(minutes),int(seconds),
dayofwk, dayofyr)
+
+def _DateFromAllLeap(JD):
+ """
+
+returns a 'datetime-like' object given Julian Day for a calendar where all
+years have 366 days.
+Julian Day is a fractional day with a resolution of 1 second.
+
+ """
+
+ # based on redate.py by David Finlayson.
+
+ if JD < 0:
+ raise ValueError, 'Julian Day must be positive'
+
+ dayofwk = int(math.fmod(int(JD + 1.5),7))
+ (F, Z) = math.modf(JD + 0.5)
+ Z = int(Z)
+ A = Z
+ B = A + 1524
+ C = int((B - 122.1)/366.)
+ D = int(366. * C)
+ E = int((B - D)/30.6001)
+
+ # Convert to date
+ day = B - D - int(30.6001 * E) + F
+ nday = B-D-123
+ if nday <= 305:
+ dayofyr = nday+60
+ else:
+ dayofyr = nday-305
+ if E < 14:
+ month = E - 1
+ else:
+ month = E - 13
+ if month > 2:
+ dayofyr = dayofyr+1
+
+ if month > 2:
+ year = C - 4716
+ else:
+ year = C - 4715
+
+ # Convert fractions of a day to time
+ (dfrac, days) = math.modf(day/1.0)
+ (hfrac, hours) = math.modf(dfrac * 24.0)
+ (mfrac, minutes) = math.modf(hfrac * 60.0)
+ seconds = round(mfrac * 60.0) # seconds are rounded
+
+ if seconds > 59:
+ seconds = 0
+ minutes = minutes + 1
+ if minutes > 59:
+ minutes = 0
+ hours = hours + 1
+ if hours > 23:
+ hours = 0
+ days = days + 1
+
+ return datetime(year,month,int(days),int(hours),int(minutes),int(seconds),
dayofwk, dayofyr)
+
+def _DateFrom360Day(JD):
+ """
+
+returns a 'datetime-like' object given Julian Day for a calendar where all
+months have 30 days.
+Julian Day is a fractional day with a resolution of 1 second.
+
+ """
+
+ if JD < 0:
+ raise ValueError, 'Julian Day must be positive'
+
+ #jd = int(360. * (year + 4716)) + int(30. * (month - 1)) + day
+ (F, Z) = math.modf(JD)
+ year = int((Z-0.5)/360.) - 4716
+ dayofyr = JD - (year+4716)*360
+ month = int((dayofyr-0.5)/30)+1
+ day = dayofyr - (month-1)*30 + F
+
+ # Convert fractions of a day to time
+ (dfrac, days) = math.modf(day/1.0)
+ (hfrac, hours) = math.modf(dfrac * 24.0)
+ (mfrac, minutes) = math.modf(hfrac * 60.0)
+ seconds = round(mfrac * 60.0) # seconds are rounded
+
+ if seconds > 59:
+ seconds = 0
+ minutes = minutes + 1
+ if minutes > 59:
+ minutes = 0
+ hours = hours + 1
+ if hours > 23:
+ hours = 0
+ days = days + 1
+
+ return
datetime(year,month,int(days),int(hours),int(minutes),int(seconds),-1,
int(dayofyr))
+
+def _dateparse(timestr,format='%Y-%m-%d %H:%M:%S'):
+ """parse a string of the form time-units since yyyy-mm-dd hh:mm:ss
+ return a tuple (units, datetimeinstance)"""
+ timestr_split = timestr.split()
+ units = timestr_split[0].lower()
+ if units not in _units:
+ raise ValueError,"units must be one of 'seconds', 'minutes', 'hours'
or 'days' (or singular version of these), got '%s'" % units
+ if timestr_split[1].lower() != 'since':
+ raise ValueError,"no 'since' in unit_string"
+ # use strptime to parse the date string.
+ n = timestr.find('since')+6
+ #year,month,day,hour,minute,second,daywk,dayyr,tz =
strptime(timestr[n:],format)
+ year,month,day,hour,minute,second = _parse_date(timestr[n:])
+ #if dayyr == -1: dayyr=1 # must have valid day of year for strftime to work
+ #return units, datetime(year, month, day, hour, minute, second, daywk,
dayyr)
+ return units, datetime(year, month, day, hour, minute, second)
+
+class utime:
+ """
+Performs conversions of netCDF time coordinate
+data to/from datetime objects.
+
+To initialize: C{t = utime(unit_string,format='%Y-%m-%d
%H:%M:%S',calendar='standard')}
+
+where
+
+B{C{unit_string}} is a string of the form
+C{'time-units since <format>'} defining the time units.
+
+B{C{format}} is a string describing a reference time. This string is converted
+to a year,month,day,hour,minute,second tuple by strptime. The default
+format is C{'%Y-%m-%d %H:%M:%S'}. See the C{time.strptime} docstring for other
+valid formats.
+
+Valid time-units are days, hours, minutes and seconds (the singular forms
+are also accepted). An example unit_string would be C{'hours
+since 0001-01-01 00:00:00'}.
+
+The B{C{calendar}} keyword describes the calendar used in the time
calculations.
+All the values currently defined in the U{CF metadata convention
+<http://www.cgd.ucar.edu/cms/eaton/cf-metadata/CF-1.0.html#time>} are
+accepted. The default is C{'standard'}, which corresponds to the mixed
+Gregorian/Julian calendar used by the C{udunits library}. Valid calendars
+are:
+
+C{'gregorian'} or C{'standard'} (default):
+
+Mixed Gregorian/Julian calendar as defined by udunits.
+
+C{'proleptic_gregorian'}:
+
+A Gregorian calendar extended to dates before 1582-10-15. That is, a year
+is a leap year if either (i) it is divisible by 4 but not by 100 or (ii)
+it is divisible by 400.
+
+C{'noleap'} or C{'365_day'}:
+
+Gregorian calendar without leap years, i.e., all years are 365 days long.
+all_leap or 366_day Gregorian calendar with every year being a leap year,
+i.e., all years are 366 days long.
+
+C{'360_day'}:
+
+All years are 360 days divided into 30 day months.
+
+C{'julian'}:
+
+Proleptic Julian calendar, extended to dates after 1582-10-5. A year is a
+leap year if it is divisible by 4.
+
+The C{L{num2date}} and C{L{date2num}} class methods can used to convert
datetime
+instances to/from the specified time units using the specified calendar.
+
+The datetime instances returned by C{num2date} are 'real' python datetime
+objects if the date falls in the Gregorian calendar (i.e.
+C{calendar='proleptic_gregorian', 'standard'} or C{'gregorian'} and
+the date is after 1582-10-15). Otherwise, they are 'phony' datetime
+objects which are actually instances of C{L{netcdftime.datetime}}. This is
+because the python datetime module cannot handle the weird dates in some
+calendars (such as C{'360_day'} and C{'all_leap'}) which don't exist in any
real
+world calendar.
+
+
+Example usage:
+
+>>> from netcdftime import utime
+>>> from datetime import datetime
+>>> cdftime = utime('hours since 0001-01-01 00:00:00')
+>>> date = datetime.now()
+>>> print date
+2006-03-17 16:04:02.561678
+>>>
+>>> t = cdftime.date2num(date)
+>>> print t
+17577328.0672
+>>>
+>>> date = cdftime.num2date(t)
+>>> print date
+2006-03-17 16:04:02
+>>>
+
+The resolution of the transformation operation is 1 second.
+
+Warning: Dates between 1582-10-5 and 1582-10-15 do not exist in the
+C{'standard'} or C{'gregorian'} calendars. An exception will be raised if you
pass
+a 'datetime-like' object in that range to the C{L{date2num}} class method.
+
+Words of Wisdom from the British MetOffice concerning reference dates
+U{http://www.metoffice.com/research/hadleycentre/models/GDT/ch26.html}:
+
+"udunits implements the mixed Gregorian/Julian calendar system, as
+followed in England, in which dates prior to 1582-10-15 are assumed to use
+the Julian calendar. Other software cannot be relied upon to handle the
+change of calendar in the same way, so for robustness it is recommended
+that the reference date be later than 1582. If earlier dates must be used,
+it should be noted that udunits treats 0 AD as identical to 1 AD."
+
[EMAIL PROTECTED] origin: datetime instance defining the origin of the netCDF
time variable.
[EMAIL PROTECTED] calendar: the calendar used (as specified by the C{calendar}
keyword).
[EMAIL PROTECTED] unit_string: a string defining the the netCDF time variable.
[EMAIL PROTECTED] units: the units part of C{unit_string} (i.e. 'days',
'hours', 'seconds').
+ """
+ def __init__(self,unit_string,format='%Y-%m-%d
%H:%M:%S',calendar='standard'):
+ """
[EMAIL PROTECTED] unit_string: a string of the form
+C{'time-units since <format>'} defining the time units.
+
[EMAIL PROTECTED] format: a string describing a reference time. This string is
converted
+to a year,month,day,hour,minute,second tuple by strptime. The default
+format is C{'%Y-%m-%d %H:%M:%S'}. See the C{time.strptime} docstring for other
+valid formats.
+Valid time-units are days, hours, minutes and seconds (the singular forms
+are also accepted). An example unit_string would be C{'hours
+since 0001-01-01 00:00:00'}.
+
[EMAIL PROTECTED] calendar: describes the calendar used in the time
calculations.
+All the values currently defined in the U{CF metadata convention
+<http://www.cgd.ucar.edu/cms/eaton/cf-metadata/CF-1.0.html#time>} are
+accepted. The default is C{'standard'}, which corresponds to the mixed
+Gregorian/Julian calendar used by the C{udunits library}. Valid calendars
+are:
+ - C{'gregorian'} or C{'standard'} (default):
+ Mixed Gregorian/Julian calendar as defined by udunits.
+ - C{'proleptic_gregorian'}:
+ A Gregorian calendar extended to dates before 1582-10-15. That is, a year
+ is a leap year if either (i) it is divisible by 4 but not by 100 or (ii)
+ it is divisible by 400.
+ - C{'noleap'} or C{'365_day'}:
+ Gregorian calendar without leap years, i.e., all years are 365 days long.
+ all_leap or 366_day Gregorian calendar with every year being a leap year,
+ i.e., all years are 366 days long.
+ -C{'360_day'}:
+ All years are 360 days divided into 30 day months.
+ -C{'julian'}:
+ Proleptic Julian calendar, extended to dates after 1582-10-5. A year is a
+ leap year if it is divisible by 4.
+
[EMAIL PROTECTED]: A class instance which may be used for converting times from
netCDF
+units to datetime objects.
+ """
+ if calendar in _calendars:
+ self.calendar = calendar
+ else:
+ raise ValueError, "calendar must be one of %s, got '%s'" %
(str(_calendars),calendar)
+ units, self.origin = _dateparse(unit_string,format=format)
+ self.units = units
+ self.unit_string = unit_string
+ if self.calendar in ['noleap','365_day'] and self.origin.month == 2
and self.origin.day == 29:
+ raise ValueError, 'cannot specify a leap day as the reference time
with the noleap calendar'
+ if self.calendar == '360_day' and self.origin.day > 30:
+ raise ValueError, 'there are only 30 days in every month with the
360_day calendar'
+ if self.calendar in ['noleap','365_day']:
+ self._jd0 = _NoLeapDayFromDate(self.origin)
+ elif self.calendar in ['all_leap','366_day']:
+ self._jd0 = _AllLeapFromDate(self.origin)
+ elif self.calendar == '360_day':
+ self._jd0 = _360DayFromDate(self.origin)
+ else:
+ self._jd0 = JulianDayFromDate(self.origin,calendar=self.calendar)
+
+ def date2num(self,date):
+ """
+Returns C{time_value} in units described by L{unit_string}, using
+the specified L{calendar}, given a 'datetime-like' object.
+
+Resolution is 1 second.
+
+If C{calendar = 'standard'} or C{'gregorian'} (indicating
+that the mixed Julian/Gregorian calendar is to be used), an
+exception will be raised if the 'datetime-like' object describes
+a date between 1582-10-5 and 1582-10-15.
+
+Works for scalars, sequences and numpy arrays.
+Returns a scalar if input is a scalar, else returns a numpy array.
+ """
+ isscalar = False
+ try:
+ date[0]
+ except:
+ isscalar = True
+ if not isscalar:
+ date = numpy.array(date)
+ shape = date.shape
+ if self.calendar in
['julian','standard','gregorian','proleptic_gregorian']:
+ if isscalar:
+ jdelta = JulianDayFromDate(date,self.calendar)-self._jd0
+ else:
+ jdelta = [JulianDayFromDate(d,self.calendar)-self._jd0 for d
in date.flat]
+ elif self.calendar in ['noleap','365_day']:
+ if date.month == 2 and date.day == 29:
+ raise ValueError, 'there is no leap day in the noleap calendar'
+ if isscalar:
+ jdelta = _NoLeapDayFromDate(date) - self._jd0
+ else:
+ jdelta = [_NoLeapDayFromDate(d)-self._jd0 for d in date.flat]
+ elif self.calendar in ['all_leap','366_day']:
+ if isscalar:
+ jdelta = _AllLeapFromDate(date) - self._jd0
+ else:
+ jdelta = [_AllLeapFromDate(d)-self._jd0 for d in date.flat]
+ elif self.calendar == '360_day':
+ if self.calendar == '360_day' and date.day > 30:
+ raise ValueError, 'there are only 30 days in every month with
the 360_day calendar'
+ if isscalar:
+ jdelta = _360DayFromDate(date) - self._jd0
+ else:
+ jdelta = [_360DayFromDate(d)-self._jd0 for d in date.flat]
+ if not isscalar:
+ jdelta = numpy.array(jdelta)
+ if self.units in ['second','seconds']:
+ jdelta = jdelta*86400.
+ elif self.units in ['minute','minutes']:
+ jdelta = jdelta*1440.
+ elif self.units in ['hours','hours']:
+ jdelta = jdelta*24.
+ if isscalar:
+ return jdelta
+ else:
+ return numpy.reshape(jdelta,shape)
+
+ def num2date(self,time_value):
+ """
+Return a 'datetime-like' object given a C{time_value} in units
+described by L{unit_string}, using L{calendar}.
+
+Resolution is 1 second.
+
+Works for scalars, sequences and numpy arrays.
+Returns a scalar if input is a scalar, else returns a numpy array.
+
+The datetime instances returned by C{num2date} are 'real' python datetime
+objects if the date falls in the Gregorian calendar (i.e.
+C{calendar='proleptic_gregorian'}, or C{calendar = 'standard'/'gregorian'} and
+the date is after 1582-10-15). Otherwise, they are 'phony' datetime
+objects which are actually instances of netcdftime.datetime. This is
+because the python datetime module cannot handle the weird dates in some
+calendars (such as C{'360_day'} and C{'all_leap'}) which don't exist in any
real
+world calendar.
+ """
+ isscalar = False
+ try:
+ time_value[0]
+ except:
+ isscalar = True
+ if not isscalar:
+ time_value = numpy.array(time_value)
+ shape = time_value.shape
+ if self.units in ['second','seconds']:
+ jdelta = time_value/86400.
+ elif self.units in ['minute','minutes']:
+ jdelta = time_value/1440.
+ elif self.units in ['hours','hours']:
+ jdelta = time_value/24.
+ elif self.units in ['day','days']:
+ jdelta = time_value
+ jd = self._jd0 + jdelta
+ if self.calendar in
['julian','standard','gregorian','proleptic_gregorian']:
+ if not isscalar:
+ date = [DateFromJulianDay(j,self.calendar) for j in jd.flat]
+ else:
+ date = DateFromJulianDay(jd,self.calendar)
+ elif self.calendar in ['noleap','365_day']:
+ if not isscalar:
+ date = [_DateFromNoLeapDay(j) for j in jd.flat]
+ else:
+ date = _DateFromNoLeapDay(jd)
+ elif self.calendar in ['all_leap','366_day']:
+ if not isscalar:
+ date = [_DateFromAllLeap(j) for j in jd.flat]
+ else:
+ date = _DateFromAllLeap(jd)
+ elif self.calendar == '360_day':
+ if not isscalar:
+ date = [_DateFrom360Day(j) for j in jd.flat]
+ else:
+ date = _DateFrom360Day(jd)
+ if isscalar:
+ return date
+ else:
+ return numpy.reshape(numpy.array(date),shape)
+
+def _parse_date(origin):
+ """Parses a date string and returns a datetime object.
+
+ This function parses the 'origin' part of the time unit. It should be
+ something like::
+
+ 2004-11-03 14:42:27.0 +2:00
+
+ Lots of things are optional; just the date is mandatory.
+
+ by Roberto D'Almeida
+
+ excerpted from coards.py - http://cheeseshop.python.org/pypi/coards/
+ """
+ # yyyy-mm-dd [hh:mm:ss[.s][ [+-]hh[:][mm]]]
+ p = re.compile( r'''(?P<year>\d{1,4}) # yyyy
+ - #
+ (?P<month>\d{1,2}) # mm or m
+ - #
+ (?P<day>\d{1,2}) # dd or d
+ #
+ (?: # [optional time and
timezone]
+ \s #
+ (?P<hour>\d{1,2}) # hh or h
+ : #
+ (?P<min>\d{1,2}) # mm or m
+ : #
+ (?P<sec>\d{1,2}) # ss or s
+ #
+ (?: # [optional decisecond]
+ \. # .
+ (?P<dsec>\d) # s
+ )? #
+ (?: # [optional timezone]
+ \s #
+ (?P<ho>[+-]? # [+ or -]
+ \d{1,2}) # hh or h
+ :? # [:]
+ (?P<mo>\d{2})? # [mm]
+ )? #
+ )? #
+ $ # EOL
+ ''', re.VERBOSE)
+
+ m = p.match(origin.strip())
+ if m:
+ c = m.groupdict(0)
+
+ # Instantiate timezone object.
+ #offset = int(c['ho'])*60 + int(c['mo'])
+ #tz = FixedOffset(offset, 'Unknown')
+
+ #return datetime(int(c['year']),
+ # int(c['month']),
+ # int(c['day']),
+ # int(c['hour']),
+ # int(c['min']),
+ # int(c['sec']),
+ # int(c['dsec']) * 100000,
+ # tz)
+ return
int(c['year']),int(c['month']),int(c['day']),int(c['hour']),int(c['min']),int(c['sec'])
+
+ raise Exception('Invalid date origin: %s' % origin)
+
+# remove the unsupposed "%s" command. But don't
+# do it if there's an even number of %s before the s
+# because those are all escaped. Can't simply
+# remove the s because the result of
+# %sY
+# should be %Y if %s isn't supported, not the
+# 4 digit year.
+_illegal_s = re.compile(r"((^|[^%])(%%)*%s)")
+
+def _findall(text, substr):
+ # Also finds overlaps
+ sites = []
+ i = 0
+ while 1:
+ j = text.find(substr, i)
+ if j == -1:
+ break
+ sites.append(j)
+ i=j+1
+ return sites
+
+# Every 28 years the calendar repeats, except through century leap
+# years where it's 6 years. But only if you're using the Gregorian
+# calendar. ;)
+
+def _strftime(dt, fmt):
+ if _illegal_s.search(fmt):
+ raise TypeError("This strftime implementation does not handle %s")
+ # don't use strftime method at all.
+ #if dt.year > 1900:
+ # return dt.strftime(fmt)
+
+ year = dt.year
+ # For every non-leap year century, advance by
+ # 6 years to get into the 28-year repeat cycle
+ delta = 2000 - year
+ off = 6*(delta // 100 + delta // 400)
+ year = year + off
+
+ # Move to around the year 2000
+ year = year + ((2000 - year)//28)*28
+ timetuple = dt.timetuple()
+ s1 = time.strftime(fmt, (year,) + timetuple[1:])
+ sites1 = _findall(s1, str(year))
+
+ s2 = time.strftime(fmt, (year+28,) + timetuple[1:])
+ sites2 = _findall(s2, str(year+28))
+
+ sites = []
+ for site in sites1:
+ if site in sites2:
+ sites.append(site)
+
+ s = s1
+ syear = "%4d" % (dt.year,)
+ for site in sites:
+ s = s[:site] + syear + s[site+4:]
+ return s
Modified: trunk/toolkits/basemap/setup.py
===================================================================
--- trunk/toolkits/basemap/setup.py 2007-12-04 19:16:57 UTC (rev 4583)
+++ trunk/toolkits/basemap/setup.py 2007-12-04 19:18:03 UTC (rev 4584)
@@ -114,10 +114,6 @@
packages = packages + ['httplib2']
package_dirs['httlib2'] = os.path.join('lib','httplib2')
-# install netcdftime
-packages = packages + ['netcdftime']
-package_dirs['httlib2'] = os.path.join('lib','netcdftime')
-
if 'setuptools' in sys.modules:
# Are we running with setuptools?
# if so, need to specify all the packages in heirarchy
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
-------------------------------------------------------------------------
SF.Net email is sponsored by: The Future of Linux Business White Paper
from Novell. From the desktop to the data center, Linux is going
mainstream. Let it simplify your IT future.
http://altfarm.mediaplex.com/ad/ck/8857-50307-18918-4
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins