Package netcdftime ::
Module netcdftime
|
|
1 """
2 Performs conversions of netCDF time coordinate data to/from datetime objects.
3 """
4 import math, numpy, re, time
5 from datetime import datetime as real_datetime
6
7 _units = ['days','hours','minutes','seconds','day','hour','minute','second']
8 _calendars = ['standard','gregorian','proleptic_gregorian','noleap','julian','all_leap','365_day','366_day','360_day']
9
10 __version__ = '0.7.2'
11
13 """
14 Phony datetime object which mimics the python datetime object,
15 but allows for dates that don't exist in the proleptic gregorian calendar.
16 Doesn't do timedelta operations, doesn't overload + and -.
17
18 Has strftime, timetuple and __repr__ methods. The format
19 of the string produced by __repr__ is controlled by self.format
20 (default %Y-%m-%d %H:%M:%S).
21
22 Instance variables are year,month,day,hour,minute,second,dayofwk,dayofyr
23 and format.
24 """
25 - def __init__(self,year,month,day,hour=0,minute=0,second=0,dayofwk=-1,dayofyr=1):
26 """dayofyr set to 1 by default - otherwise time.strftime will complain"""
27 self.year=year
28 self.month=month
29 self.day=day
30 self.hour=hour
31 self.minute=minute
32 self.dayofwk=dayofwk
33 self.dayofyr=dayofyr
34 self.second=second
35 self.format='%Y-%m-%d %H:%M:%S'
37 if format is None:
38 format = self.format
39 return _strftime(self,format)
41 return (self.year,self.month,self.day,self.hour,self.minute,self.second,self.dayofwk,self.dayofyr,-1)
44
46
47 """
48
49 creates a Julian Day from a 'datetime-like' object. Returns the fractional
50 Julian Day (resolution 1 second).
51
52 if calendar='standard' or 'gregorian' (default), Julian day follows Julian
53 Calendar on and before 1582-10-5, Gregorian calendar after 1582-10-15.
54
55 if calendar='proleptic_gregorian', Julian Day follows gregorian calendar.
56
57 if calendar='julian', Julian Day follows julian calendar.
58
59 Algorithm:
60
61 Meeus, Jean (1998) Astronomical Algorithms (2nd Edition). Willmann-Bell,
62 Virginia. p. 63
63
64 """
65
66
67
68 year=date.year; month=date.month; day=date.day
69 hour=date.hour; minute=date.minute; second=date.second
70
71 day = day + hour/24.0 + minute/1440.0 + second/86400.0
72
73
74 if (month < 3):
75 month = month + 12
76 year = year - 1
77
78 A = int(year/100)
79
80 jd = int(365.25 * (year + 4716)) + int(30.6001 * (month + 1)) + \
81 day - 1524.5
82
83
84
85
86 if calendar in ['standard','gregorian']:
87 if jd >= 2299170.5:
88
89 B = 2 - A + int(A/4)
90 elif jd < 2299160.5:
91
92 B = 0
93 else:
94 raise ValueError, 'impossible date (falls in gap between end of Julian calendar and beginning of Gregorian calendar'
95 elif calendar == 'proleptic_gregorian':
96 B = 2 - A + int(A/4)
97 elif calendar == 'julian':
98 B = 0
99 else:
100 raise ValueError, 'unknown calendar, must be one of julian,standard,gregorian,proleptic_gregorian, got %s' % calendar
101
102
103 jd = jd + B
104
105 return jd
106
108
109 """
110
111 creates a Julian Day for a calendar with no leap years from a datetime
112 instance. Returns the fractional Julian Day (resolution 1 second).
113
114 """
115
116 year=date.year; month=date.month; day=date.day
117 hour=date.hour; minute=date.minute; second=date.second
118
119 day = day + hour/24.0 + minute/1440.0 + second/86400.0
120
121
122 if (month < 3):
123 month = month + 12
124 year = year - 1
125
126 jd = int(365. * (year + 4716)) + int(30.6001 * (month + 1)) + \
127 day - 1524.5
128
129 return jd
130
132
133 """
134
135 creates a Julian Day for a calendar where all years have 366 days from
136 a 'datetime-like' object.
137 Returns the fractional Julian Day (resolution 1 second).
138
139 """
140
141 year=date.year; month=date.month; day=date.day
142 hour=date.hour; minute=date.minute; second=date.second
143
144 day = day + hour/24.0 + minute/1440.0 + second/86400.0
145
146
147 if (month < 3):
148 month = month + 12
149 year = year - 1
150
151 jd = int(366. * (year + 4716)) + int(30.6001 * (month + 1)) + \
152 day - 1524.5
153
154 return jd
155
157
158 """
159
160 creates a Julian Day for a calendar where all months have 30 daysfrom
161 a 'datetime-like' object.
162 Returns the fractional Julian Day (resolution 1 second).
163
164 """
165
166 year=date.year; month=date.month; day=date.day
167 hour=date.hour; minute=date.minute; second=date.second
168
169 day = day + hour/24.0 + minute/1440.0 + second/86400.0
170
171 jd = int(360. * (year + 4716)) + int(30. * (month - 1)) + day
172
173 return jd
174
176 """
177
178 returns a 'datetime-like' object given Julian Day. Julian Day is a
179 fractional day with a resolution of 1 second.
180
181 if calendar='standard' or 'gregorian' (default), Julian day follows Julian
182 Calendar on and before 1582-10-5, Gregorian calendar after 1582-10-15.
183
184 if calendar='proleptic_gregorian', Julian Day follows gregorian calendar.
185
186 if calendar='julian', Julian Day follows julian calendar.
187
188 The datetime object is a 'real' datetime object if the date falls in
189 the Gregorian calendar (i.e. calendar='proleptic_gregorian', or
190 calendar = 'standard'/'gregorian' and the date is after 1582-10-15).
191 Otherwise, it's a 'phony' datetime object which is actually an instance
192 of netcdftime.datetime.
193
194
195 Algorithm:
196
197 Meeus, Jean (1998) Astronomical Algorithms (2nd Edition). Willmann-Bell,
198 Virginia. p. 63
199
200 """
201
202
203
204 if JD < 0:
205 raise ValueError, 'Julian Day must be positive'
206
207 dayofwk = int(math.fmod(int(JD + 1.5),7))
208 (F, Z) = math.modf(JD + 0.5)
209 Z = int(Z)
210 if calendar in ['standard','gregorian']:
211 if JD < 2299160.5:
212 A = Z
213 else:
214 alpha = int((Z - 1867216.25)/36524.25)
215 A = Z + 1 + alpha - int(alpha/4)
216
217 elif calendar == 'proleptic_gregorian':
218 alpha = int((Z - 1867216.25)/36524.25)
219 A = Z + 1 + alpha - int(alpha/4)
220 elif calendar == 'julian':
221 A = Z
222 else:
223 raise ValueError, 'unknown calendar, must be one of julian,standard,gregorian,proleptic_gregorian, got %s' % calendar
224
225 B = A + 1524
226 C = int((B - 122.1)/365.25)
227 D = int(365.25 * C)
228 E = int((B - D)/30.6001)
229
230
231 day = B - D - int(30.6001 * E) + F
232 nday = B-D-123
233 if nday <= 305:
234 dayofyr = nday+60
235 else:
236 dayofyr = nday-305
237 if E < 14:
238 month = E - 1
239 else:
240 month = E - 13
241
242 if month > 2:
243 year = C - 4716
244 else:
245 year = C - 4715
246
247
248 leap = 0
249 if year % 4 == 0:
250 leap = 1
251 if calendar == 'proleptic_gregorian' or \
252 (calendar in ['standard','gregorian'] and JD >= 2299160.5):
253 if year % 100 == 0 and year % 400 != 0:
254 print year % 100, year % 400
255 leap = 0
256 if leap and month > 2:
257 dayofyr = dayofyr + leap
258
259
260 (dfrac, days) = math.modf(day/1.0)
261 (hfrac, hours) = math.modf(dfrac * 24.0)
262 (mfrac, minutes) = math.modf(hfrac * 60.0)
263 seconds = round(mfrac * 60.0)
264
265 if seconds > 59:
266 seconds = 0
267 minutes = minutes + 1
268 if minutes > 59:
269 minutes = 0
270 hours = hours + 1
271 if hours > 23:
272 hours = 0
273 days = days + 1
274
275
276 if calendar == 'proleptic_gregorian' or \
277 (calendar in ['standard','gregorian'] and JD >= 2299160.5):
278 return real_datetime(year,month,int(days),int(hours),int(minutes),int(seconds))
279 else:
280
281 return datetime(year,month,int(days),int(hours),int(minutes),int(seconds),dayofwk,dayofyr)
282
284 """
285
286 returns a 'datetime-like' object given Julian Day for a calendar with no leap
287 days. Julian Day is a fractional day with a resolution of 1 second.
288
289 """
290
291
292
293 if JD < 0:
294 raise ValueError, 'Julian Day must be positive'
295
296 dayofwk = int(math.fmod(int(JD + 1.5),7))
297 (F, Z) = math.modf(JD + 0.5)
298 Z = int(Z)
299 A = Z
300 B = A + 1524
301 C = int((B - 122.1)/365.)
302 D = int(365. * C)
303 E = int((B - D)/30.6001)
304
305
306 day = B - D - int(30.6001 * E) + F
307 nday = B-D-123
308 if nday <= 305:
309 dayofyr = nday+60
310 else:
311 dayofyr = nday-305
312 if E < 14:
313 month = E - 1
314 else:
315 month = E - 13
316
317 if month > 2:
318 year = C - 4716
319 else:
320 year = C - 4715
321
322
323 (dfrac, days) = math.modf(day/1.0)
324 (hfrac, hours) = math.modf(dfrac * 24.0)
325 (mfrac, minutes) = math.modf(hfrac * 60.0)
326 seconds = round(mfrac * 60.0)
327
328 if seconds > 59:
329 seconds = 0
330 minutes = minutes + 1
331 if minutes > 59:
332 minutes = 0
333 hours = hours + 1
334 if hours > 23:
335 hours = 0
336 days = days + 1
337
338 return datetime(year,month,int(days),int(hours),int(minutes),int(seconds), dayofwk, dayofyr)
339
341 """
342
343 returns a 'datetime-like' object given Julian Day for a calendar where all
344 years have 366 days.
345 Julian Day is a fractional day with a resolution of 1 second.
346
347 """
348
349
350
351 if JD < 0:
352 raise ValueError, 'Julian Day must be positive'
353
354 dayofwk = int(math.fmod(int(JD + 1.5),7))
355 (F, Z) = math.modf(JD + 0.5)
356 Z = int(Z)
357 A = Z
358 B = A + 1524
359 C = int((B - 122.1)/366.)
360 D = int(366. * C)
361 E = int((B - D)/30.6001)
362
363
364 day = B - D - int(30.6001 * E) + F
365 nday = B-D-123
366 if nday <= 305:
367 dayofyr = nday+60
368 else:
369 dayofyr = nday-305
370 if E < 14:
371 month = E - 1
372 else:
373 month = E - 13
374 if month > 2:
375 dayofyr = dayofyr+1
376
377 if month > 2:
378 year = C - 4716
379 else:
380 year = C - 4715
381
382
383 (dfrac, days) = math.modf(day/1.0)
384 (hfrac, hours) = math.modf(dfrac * 24.0)
385 (mfrac, minutes) = math.modf(hfrac * 60.0)
386 seconds = round(mfrac * 60.0)
387
388 if seconds > 59:
389 seconds = 0
390 minutes = minutes + 1
391 if minutes > 59:
392 minutes = 0
393 hours = hours + 1
394 if hours > 23:
395 hours = 0
396 days = days + 1
397
398 return datetime(year,month,int(days),int(hours),int(minutes),int(seconds), dayofwk, dayofyr)
399
401 """
402
403 returns a 'datetime-like' object given Julian Day for a calendar where all
404 months have 30 days.
405 Julian Day is a fractional day with a resolution of 1 second.
406
407 """
408
409 if JD < 0:
410 raise ValueError, 'Julian Day must be positive'
411
412
413 (F, Z) = math.modf(JD)
414 year = int((Z-0.5)/360.) - 4716
415 dayofyr = JD - (year+4716)*360
416 month = int((dayofyr-0.5)/30)+1
417 day = dayofyr - (month-1)*30 + F
418
419
420 (dfrac, days) = math.modf(day/1.0)
421 (hfrac, hours) = math.modf(dfrac * 24.0)
422 (mfrac, minutes) = math.modf(hfrac * 60.0)
423 seconds = round(mfrac * 60.0)
424
425 if seconds > 59:
426 seconds = 0
427 minutes = minutes + 1
428 if minutes > 59:
429 minutes = 0
430 hours = hours + 1
431 if hours > 23:
432 hours = 0
433 days = days + 1
434
435 return datetime(year,month,int(days),int(hours),int(minutes),int(seconds),-1, int(dayofyr))
436
438 """parse a string of the form time-units since yyyy-mm-dd hh:mm:ss
439 return a tuple (units, datetimeinstance)"""
440 timestr_split = timestr.split()
441 units = timestr_split[0].lower()
442 if units not in _units:
443 raise ValueError,"units must be one of 'seconds', 'minutes', 'hours' or 'days' (or singular version of these), got '%s'" % units
444 if timestr_split[1].lower() != 'since':
445 raise ValueError,"no 'since' in unit_string"
446
447 n = timestr.find('since')+6
448 year,month,day,hour,minute,second,utc_offset = _parse_date(timestr[n:])
449 return units, utc_offset, datetime(year, month, day, hour, minute, second)
450
452 """
453 Performs conversions of netCDF time coordinate
454 data to/from datetime objects.
455
456 To initialize: C{t = utime(unit_string,calendar='standard')}
457
458 where
459
460 B{C{unit_string}} is a string of the form
461 C{'time-units since <time-origin>'} defining the time units.
462
463 Valid time-units are days, hours, minutes and seconds (the singular forms
464 are also accepted). An example unit_string would be C{'hours
465 since 0001-01-01 00:00:00'}.
466
467 The B{C{calendar}} keyword describes the calendar used in the time calculations.
468 All the values currently defined in the U{CF metadata convention
469 <http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.1/cf-conventions.html#time-coordinate>}
470 are accepted. The default is C{'standard'}, which corresponds to the mixed
471 Gregorian/Julian calendar used by the C{udunits library}. Valid calendars
472 are:
473
474 C{'gregorian'} or C{'standard'} (default):
475
476 Mixed Gregorian/Julian calendar as defined by udunits.
477
478 C{'proleptic_gregorian'}:
479
480 A Gregorian calendar extended to dates before 1582-10-15. That is, a year
481 is a leap year if either (i) it is divisible by 4 but not by 100 or (ii)
482 it is divisible by 400.
483
484 C{'noleap'} or C{'365_day'}:
485
486 Gregorian calendar without leap years, i.e., all years are 365 days long.
487 all_leap or 366_day Gregorian calendar with every year being a leap year,
488 i.e., all years are 366 days long.
489
490 C{'360_day'}:
491
492 All years are 360 days divided into 30 day months.
493
494 C{'julian'}:
495
496 Proleptic Julian calendar, extended to dates after 1582-10-5. A year is a
497 leap year if it is divisible by 4.
498
499 The C{L{num2date}} and C{L{date2num}} class methods can used to convert datetime
500 instances to/from the specified time units using the specified calendar.
501
502 The datetime instances returned by C{num2date} are 'real' python datetime
503 objects if the date falls in the Gregorian calendar (i.e.
504 C{calendar='proleptic_gregorian', 'standard'} or C{'gregorian'} and
505 the date is after 1582-10-15). Otherwise, they are 'phony' datetime
506 objects which are actually instances of C{L{netcdftime.datetime}}. This is
507 because the python datetime module cannot handle the weird dates in some
508 calendars (such as C{'360_day'} and C{'all_leap'}) which don't exist in any real
509 world calendar.
510
511
512 Example usage:
513
514 >>> from netcdftime import utime
515 >>> from datetime import datetime
516 >>> cdftime = utime('hours since 0001-01-01 00:00:00')
517 >>> date = datetime.now()
518 >>> print date
519 2006-03-17 16:04:02.561678
520 >>>
521 >>> t = cdftime.date2num(date)
522 >>> print t
523 17577328.0672
524 >>>
525 >>> date = cdftime.num2date(t)
526 >>> print date
527 2006-03-17 16:04:02
528 >>>
529
530 The resolution of the transformation operation is 1 second.
531
532 Warning: Dates between 1582-10-5 and 1582-10-15 do not exist in the
533 C{'standard'} or C{'gregorian'} calendars. An exception will be raised if you pass
534 a 'datetime-like' object in that range to the C{L{date2num}} class method.
535
536 Words of Wisdom from the British MetOffice concerning reference dates:
537
538 "udunits implements the mixed Gregorian/Julian calendar system, as
539 followed in England, in which dates prior to 1582-10-15 are assumed to use
540 the Julian calendar. Other software cannot be relied upon to handle the
541 change of calendar in the same way, so for robustness it is recommended
542 that the reference date be later than 1582. If earlier dates must be used,
543 it should be noted that udunits treats 0 AD as identical to 1 AD."
544
545 @ivar origin: datetime instance defining the origin of the netCDF time variable.
546 @ivar calendar: the calendar used (as specified by the C{calendar} keyword).
547 @ivar unit_string: a string defining the the netCDF time variable.
548 @ivar units: the units part of C{unit_string} (i.e. 'days', 'hours', 'seconds').
549 """
550 - def __init__(self,unit_string,calendar='standard'):
551 """
552 @param unit_string: a string of the form
553 C{'time-units since <time-origin>'} defining the time units.
554
555 Valid time-units are days, hours, minutes and seconds (the singular forms
556 are also accepted). An example unit_string would be C{'hours
557 since 0001-01-01 00:00:00'}.
558
559 @keyword calendar: describes the calendar used in the time calculations.
560 All the values currently defined in the U{CF metadata convention
561 <http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.1/cf-conventions.html#time-coordinate>}
562 are accepted. The default is C{'standard'}, which corresponds to the mixed
563 Gregorian/Julian calendar used by the C{udunits library}. Valid calendars
564 are:
565 - C{'gregorian'} or C{'standard'} (default):
566 Mixed Gregorian/Julian calendar as defined by udunits.
567 - C{'proleptic_gregorian'}:
568 A Gregorian calendar extended to dates before 1582-10-15. That is, a year
569 is a leap year if either (i) it is divisible by 4 but not by 100 or (ii)
570 it is divisible by 400.
571 - C{'noleap'} or C{'365_day'}:
572 Gregorian calendar without leap years, i.e., all years are 365 days long.
573 - C{'all_leap'} or C{'366_day'}:
574 Gregorian calendar with every year being a leap year, i.e.,
575 all years are 366 days long.
576 -C{'360_day'}:
577 All years are 360 days divided into 30 day months.
578 -C{'julian'}:
579 Proleptic Julian calendar, extended to dates after 1582-10-5. A year is a
580 leap year if it is divisible by 4.
581
582 @returns: A class instance which may be used for converting times from netCDF
583 units to datetime objects.
584 """
585 if calendar in _calendars:
586 self.calendar = calendar
587 else:
588 raise ValueError, "calendar must be one of %s, got '%s'" % (str(_calendars),calendar)
589 units, tzoffset, self.origin = _dateparse(unit_string)
590 self.tzoffset = tzoffset
591 self.units = units
592 self.unit_string = unit_string
593 if self.calendar in ['noleap','365_day'] and self.origin.month == 2 and self.origin.day == 29:
594 raise ValueError, 'cannot specify a leap day as the reference time with the noleap calendar'
595 if self.calendar == '360_day' and self.origin.day > 30:
596 raise ValueError, 'there are only 30 days in every month with the 360_day calendar'
597 if self.calendar in ['noleap','365_day']:
598 self._jd0 = _NoLeapDayFromDate(self.origin)
599 elif self.calendar in ['all_leap','366_day']:
600 self._jd0 = _AllLeapFromDate(self.origin)
601 elif self.calendar == '360_day':
602 self._jd0 = _360DayFromDate(self.origin)
603 else:
604 self._jd0 = JulianDayFromDate(self.origin,calendar=self.calendar)
605
607 """
608 Returns C{time_value} in units described by L{unit_string}, using
609 the specified L{calendar}, given a 'datetime-like' object.
610
611 The datetime object must represent UTC with no time-zone offset.
612 If there is a time-zone offset implied by L{unit_string}, it will
613 be applied to the returned numeric values.
614
615 Resolution is 1 second.
616
617 If C{calendar = 'standard'} or C{'gregorian'} (indicating
618 that the mixed Julian/Gregorian calendar is to be used), an
619 exception will be raised if the 'datetime-like' object describes
620 a date between 1582-10-5 and 1582-10-15.
621
622 Works for scalars, sequences and numpy arrays.
623 Returns a scalar if input is a scalar, else returns a numpy array.
624 """
625 isscalar = False
626 try:
627 date[0]
628 except:
629 isscalar = True
630 if not isscalar:
631 date = numpy.array(date)
632 shape = date.shape
633 if self.calendar in ['julian','standard','gregorian','proleptic_gregorian']:
634 if isscalar:
635 jdelta = JulianDayFromDate(date,self.calendar)-self._jd0
636 else:
637 jdelta = [JulianDayFromDate(d,self.calendar)-self._jd0 for d in date.flat]
638 elif self.calendar in ['noleap','365_day']:
639 if date.month == 2 and date.day == 29:
640 raise ValueError, 'there is no leap day in the noleap calendar'
641 if isscalar:
642 jdelta = _NoLeapDayFromDate(date) - self._jd0
643 else:
644 jdelta = [_NoLeapDayFromDate(d)-self._jd0 for d in date.flat]
645 elif self.calendar in ['all_leap','366_day']:
646 if isscalar:
647 jdelta = _AllLeapFromDate(date) - self._jd0
648 else:
649 jdelta = [_AllLeapFromDate(d)-self._jd0 for d in date.flat]
650 elif self.calendar == '360_day':
651 if self.calendar == '360_day' and date.day > 30:
652 raise ValueError, 'there are only 30 days in every month with the 360_day calendar'
653 if isscalar:
654 jdelta = _360DayFromDate(date) - self._jd0
655 else:
656 jdelta = [_360DayFromDate(d)-self._jd0 for d in date.flat]
657 if not isscalar:
658 jdelta = numpy.array(jdelta)
659
660 if self.units in ['second','seconds']:
661 jdelta = jdelta*86400. + self.tzoffset*60.
662 elif self.units in ['minute','minutes']:
663 jdelta = jdelta*1440. + self.tzoffset
664 elif self.units in ['hour','hours']:
665 jdelta = jdelta*24. + self.tzoffset/60.
666 elif self.units in ['day','days']:
667 jdelta = jdelta + self.tzoffset/1440.
668 if isscalar:
669 return jdelta
670 else:
671 return numpy.reshape(jdelta,shape)
672
674 """
675 Return a 'datetime-like' object given a C{time_value} in units
676 described by L{unit_string}, using L{calendar}.
677
678 dates are in UTC with no offset, even if L{unit_string} contains
679 a time zone offset from UTC.
680
681 Resolution is 1 second.
682
683 Works for scalars, sequences and numpy arrays.
684 Returns a scalar if input is a scalar, else returns a numpy array.
685
686 The datetime instances returned by C{num2date} are 'real' python datetime
687 objects if the date falls in the Gregorian calendar (i.e.
688 C{calendar='proleptic_gregorian'}, or C{calendar = 'standard'/'gregorian'} and
689 the date is after 1582-10-15). Otherwise, they are 'phony' datetime
690 objects which are actually instances of netcdftime.datetime. This is
691 because the python datetime module cannot handle the weird dates in some
692 calendars (such as C{'360_day'} and C{'all_leap'}) which
693 do not exist in any real world calendar.
694 """
695 isscalar = False
696 try:
697 time_value[0]
698 except:
699 isscalar = True
700 if not isscalar:
701 time_value = numpy.array(time_value, dtype='d')
702 shape = time_value.shape
703
704 if self.units in ['second','seconds']:
705 jdelta = time_value/86400. - self.tzoffset/1440.
706 elif self.units in ['minute','minutes']:
707 jdelta = time_value/1440. - self.tzoffset/1440.
708 elif self.units in ['hour','hours']:
709 jdelta = time_value/24. - self.tzoffset/1440.
710 elif self.units in ['day','days']:
711 jdelta = time_value - self.tzoffset/1440.
712 jd = self._jd0 + jdelta
713 if self.calendar in ['julian','standard','gregorian','proleptic_gregorian']:
714 if not isscalar:
715 date = [DateFromJulianDay(j,self.calendar) for j in jd.flat]
716 else:
717 date = DateFromJulianDay(jd,self.calendar)
718 elif self.calendar in ['noleap','365_day']:
719 if not isscalar:
720 date = [_DateFromNoLeapDay(j) for j in jd.flat]
721 else:
722 date = _DateFromNoLeapDay(jd)
723 elif self.calendar in ['all_leap','366_day']:
724 if not isscalar:
725 date = [_DateFromAllLeap(j) for j in jd.flat]
726 else:
727 date = _DateFromAllLeap(jd)
728 elif self.calendar == '360_day':
729 if not isscalar:
730 date = [_DateFrom360Day(j) for j in jd.flat]
731 else:
732 date = _DateFrom360Day(jd)
733 if isscalar:
734 return date
735 else:
736 return numpy.reshape(numpy.array(date),shape)
737
739 """Parses a date string and returns a tuple
740 (year,month,day,hour,minute,second,utc_offset).
741 utc_offset is in minutes.
742
743 This function parses the 'origin' part of the time unit. It should be
744 something like::
745
746 2004-11-03 14:42:27.0 +2:00
747
748 Lots of things are optional; just the date is mandatory.
749
750 by Roberto De Almeida
751
752 excerpted from coards.py - http://cheeseshop.python.org/pypi/coards/
753 """
754
755 p = re.compile( r'''(?P<year>\d{1,4}) # yyyy
756 - #
757 (?P<month>\d{1,2}) # mm or m
758 - #
759 (?P<day>\d{1,2}) # dd or d
760 #
761 (?: # [optional time and timezone]
762 \s #
763 (?P<hour>\d{1,2}) # hh or h
764 : #
765 (?P<min>\d{1,2}) # mm or m
766 (?:
767 \:
768 (?P<sec>\d{1,2}) # ss or s (optional)
769 )?
770 #
771 (?: # [optional decisecond]
772 \. # .
773 (?P<dsec>\d) # s
774 )? #
775 (?: # [optional timezone]
776 \s #
777 (?P<ho>[+-]? # [+ or -]
778 \d{1,2}) # hh or h
779 :? # [:]
780 (?P<mo>\d{2})? # [mm]
781 )? #
782 )? #
783 $ # EOL
784 ''', re.VERBOSE)
785
786 m = p.match(origin.strip())
787 if m:
788 c = m.groupdict(0)
789
790 offset = int(c['ho'])*60 + int(c['mo'])
791 return int(c['year']),int(c['month']),int(c['day']),int(c['hour']),int(c['min']),int(c['sec']),offset
792
793 raise Exception('Invalid date origin: %s' % origin)
794
795
796
797
798
799
800
801
802 _illegal_s = re.compile(r"((^|[^%])(%%)*%s)")
803
805
806 sites = []
807 i = 0
808 while 1:
809 j = text.find(substr, i)
810 if j == -1:
811 break
812 sites.append(j)
813 i=j+1
814 return sites
815
816
817
818
819
821 if _illegal_s.search(fmt):
822 raise TypeError("This strftime implementation does not handle %s")
823
824
825
826
827 year = dt.year
828
829
830 delta = 2000 - year
831 off = 6*(delta // 100 + delta // 400)
832 year = year + off
833
834
835 year = year + ((2000 - year)//28)*28
836 timetuple = dt.timetuple()
837 s1 = time.strftime(fmt, (year,) + timetuple[1:])
838 sites1 = _findall(s1, str(year))
839
840 s2 = time.strftime(fmt, (year+28,) + timetuple[1:])
841 sites2 = _findall(s2, str(year+28))
842
843 sites = []
844 for site in sites1:
845 if site in sites2:
846 sites.append(site)
847
848 s = s1
849 syear = "%4d" % (dt.year,)
850 for site in sites:
851 s = s[:site] + syear + s[site+4:]
852 return s
853
854 -def date2num(dates,units,calendar='standard'):
855 """
856 date2num(dates,units,calendar='standard')
857
858 Return numeric time values given datetime objects. The units
859 of the numeric time values are described by the L{units} argument
860 and the L{calendar} keyword. The datetime objects must
861 be in UTC with no time-zone offset. If there is a
862 time-zone offset in C{units}, it will be applied to the
863 returned numeric values.
864
865 Like the matplotlib C{date2num} function, except that it allows
866 for different units and calendars. Behaves the same if
867 C{units = 'days since 0001-01-01 00:00:00'} and
868 C{calendar = 'proleptic_gregorian'}.
869
870 @param dates: A datetime object or a sequence of datetime objects.
871 The datetime objects should not include a time-zone offset.
872
873 @param units: a string of the form C{'B{time units} since B{reference time}}'
874 describing the time units. B{C{time units}} can be days, hours, minutes
875 or seconds. B{C{reference time}} is the time origin. A valid choice
876 would be units=C{'hours since 1800-01-01 00:00:00 -6:00'}.
877
878 @param calendar: describes the calendar used in the time calculations.
879 All the values currently defined in the U{CF metadata convention
880 <http://cf-pcmdi.llnl.gov/documents/cf-conventions/>} are supported.
881 Valid calendars C{'standard', 'gregorian', 'proleptic_gregorian'
882 'noleap', '365_day', '360_day', 'julian', 'all_leap', '366_day'}.
883 Default is C{'standard'}, which is a mixed Julian/Gregorian calendar.
884
885 @return: a numeric time value, or an array of numeric time values.
886
887 The maximum resolution of the numeric time values is 1 second.
888 """
889 cdftime = utime(units,calendar=calendar)
890 return cdftime.date2num(dates)
891
892 -def num2date(times,units,calendar='standard'):
893 """
894 num2date(times,units,calendar='standard')
895
896 Return datetime objects given numeric time values. The units
897 of the numeric time values are described by the C{units} argument
898 and the C{calendar} keyword. The returned datetime objects represent
899 UTC with no time-zone offset, even if the specified
900 C{units} contain a time-zone offset.
901
902 Like the matplotlib C{num2date} function, except that it allows
903 for different units and calendars. Behaves the same if
904 C{units = 'days since 001-01-01 00:00:00'} and
905 C{calendar = 'proleptic_gregorian'}.
906
907 @param times: numeric time values. Maximum resolution is 1 second.
908
909 @param units: a string of the form C{'B{time units} since B{reference time}}'
910 describing the time units. B{C{time units}} can be days, hours, minutes
911 or seconds. B{C{reference time}} is the time origin. A valid choice
912 would be units=C{'hours since 1800-01-01 00:00:00 -6:00'}.
913
914 @param calendar: describes the calendar used in the time calculations.
915 All the values currently defined in the U{CF metadata convention
916 <http://cf-pcmdi.llnl.gov/documents/cf-conventions/>} are supported.
917 Valid calendars C{'standard', 'gregorian', 'proleptic_gregorian'
918 'noleap', '365_day', '360_day', 'julian', 'all_leap', '366_day'}.
919 Default is C{'standard'}, which is a mixed Julian/Gregorian calendar.
920
921 @return: a datetime instance, or an array of datetime instances.
922
923 The datetime instances returned are 'real' python datetime
924 objects if the date falls in the Gregorian calendar (i.e.
925 C{calendar='proleptic_gregorian'}, or C{calendar = 'standard'} or C{'gregorian'}
926 and the date is after 1582-10-15). Otherwise, they are 'phony' datetime
927 objects which support some but not all the methods of 'real' python
928 datetime objects. This is because the python datetime module cannot
929 the uses the C{'proleptic_gregorian'} calendar, even before the switch
930 occured from the Julian calendar in 1582. The datetime instances
931 do not contain a time-zone offset, even if the specified C{units}
932 contains one.
933 """
934 cdftime = utime(units,calendar=calendar)
935 return cdftime.num2date(times)
936
938 """Return True if the time indices given correspond to the given dates,
939 False otherwise.
940
941 Parameters:
942
943 indices : sequence of integers
944 Positive integers indexing the time variable.
945
946 dates : sequence of datetime objects
947 Reference dates.
948
949 nctime : netCDF Variable object
950 NetCDF time object.
951
952 calendar : string
953 Calendar of nctime.
954 """
955 if (indices <0).any():
956 return False
957
958 if (indices >= nctime.shape[0]).any():
959 return False
960
961 t = nctime[indices]
962
963
964
965
966 return numpy.all( num2date(t, nctime.units, calendar) == dates)
967
968
969
970 -def date2index(dates, nctime, calendar=None, select='exact'):
971 """
972 date2index(dates, nctime, calendar=None, select='exact')
973
974 Return indices of a netCDF time variable corresponding to the given dates.
975
976 @param dates: A datetime object or a sequence of datetime objects.
977 The datetime objects should not include a time-zone offset.
978
979 @param nctime: A netCDF time variable object. The nctime object must have a
980 C{units} attribute. The entries are assumed to be stored in increasing
981 order.
982
983 @param calendar: Describes the calendar used in the time calculation.
984 Valid calendars C{'standard', 'gregorian', 'proleptic_gregorian'
985 'noleap', '365_day', '360_day', 'julian', 'all_leap', '366_day'}.
986 Default is C{'standard'}, which is a mixed Julian/Gregorian calendar
987 If C{calendar} is None, its value is given by C{nctime.calendar} or
988 C{standard} if no such attribute exists.
989
990 @param select: C{'exact', 'before', 'after', 'nearest'}
991 The index selection method. C{exact} will return the indices perfectly
992 matching the dates given. C{before} and C{after} will return the indices
993 corresponding to the dates just before or just after the given dates if
994 an exact match cannot be found. C{nearest} will return the indices that
995 correpond to the closest dates.
996 """
997
998 if calendar == None:
999 calendar = getattr(nctime, 'calendar', 'standard')
1000
1001 num = numpy.atleast_1d(date2num(dates, nctime.units, calendar))
1002 N = len(nctime)
1003
1004
1005
1006 t0, t1 = nctime[:2]
1007 dt = t1 - t0
1008 index = numpy.array((num-t0)/dt, int)
1009
1010
1011
1012
1013 if not _check_index(index, dates, nctime, calendar):
1014
1015
1016 import bisect
1017 index = numpy.array([bisect.bisect_left(nctime, n) for n in num], int)
1018
1019 after = index == N
1020 before = index == 0
1021
1022 if select in ['before', 'exact'] and numpy.any(before):
1023 raise ValueError, 'At least one of the dates given is before the first date in `nctime`.'
1024
1025 if select in ['after', 'exact'] and numpy.any(after):
1026 raise ValueError, 'At least one of the dates given is after the last date in `nctime`.'
1027
1028
1029
1030
1031
1032 index[after] = N-1
1033 ncnum = numpy.squeeze([nctime[i] for i in index])
1034 mismatch = numpy.nonzero(ncnum != num)[0]
1035
1036 if select == 'exact':
1037 if len(mismatch) > 0:
1038 raise ValueError, 'Some of the dates specified were not found in the `nctime` variable.'
1039
1040 elif select == 'before':
1041 index[after] = N
1042 index[mismatch] -= 1
1043
1044 elif select == 'after':
1045 pass
1046
1047 elif select == 'nearest':
1048 nearest_to_left = num[mismatch] < numpy.array( [nctime[i-1] + nctime[i] for i in index[mismatch]]) / 2.
1049 index[mismatch] = index[mismatch] - 1 * nearest_to_left
1050
1051 else:
1052 raise ValueError("%s is not an option for the `select` argument."%select)
1053
1054
1055
1056 index[before] = 0
1057
1058
1059 return _toscalar(index)
1060
1061
1063 if a.shape in [(),(1,)]:
1064 return a.item()
1065 else:
1066 return a
1067