source: TI03-DataExtractor/trunk/pydxs/DateTimeManager.py @ 1715

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI03-DataExtractor/trunk/pydxs/DateTimeManager.py@1715
Revision 1715, 12.6 KB checked in by astephen, 13 years ago (diff)

Merged with titania version.

Line 
1#!/usr/bin/env python
2
3#   Copyright (C) 2004 CCLRC & NERC( Natural Environment Research Council ).
4#   This software may be distributed under the terms of the
5#   Q Public License, version 1.0 or later. http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
6
7helpMessage="""
8
9DateTimeManager.py
10==================
11
12Holds the class DateTimeManager that is a component time object copied
13from Bob Drach's cdtime within CDAT (Thanks Bob!). The reason for
14this duplication is that cdtime has dependencies on other software
15and is partly written in C. This version is entirely python and is
16therefore more portable.
17
18The class DateTimeManager has the following methods exposed to the user:
19
20    add(n, units) -  to add an interval to the current time object.
21    sub(n, units) - to subtract an interval to the current time object.
22    createList(s, e, i) - generate a list of times from s(tart) to e(nd)
23                        with i(nterval).
24    printtime(format_string)     - prints the time using typical python time formatting.
25    getDaysInMonth(month, year) - returns the number of days in a given month.
26
27The createList(s, e, i) function is a wrapper around DateTimeManager.createList() at the
28module level.
29
30
31Usage:
32======
33
34To create a date-time instance for midday Christmas day 2003:
35
36mytime=DateTimeManager(2003, 12, 25, 12, 0, 0)
37
38To add 3 months to the instance:
39
40mytime.add(3, "months")
41
42To create a list of dates and times:
43
44mylist=createList("1999-01-01 00:00:00", "1999-01-22 12:00:00", (6, "hour"))
45
46
47"""
48
49# Import standard library modules
50import re, types, time
51
52def daysInMonth(month, year):
53    """
54    Function wrapper around DateTimeManager.getDaysInMonth() method.
55    """
56    dt=DateTimeManager()
57    return dt.getDaysInMonth(month, year) 
58
59
60def createList(start, end, interval=(6, "hour"), listtype="string", formatstring="%Y-%m-%d %H:%M:%S"):
61    """
62    Function wrappper around DateTimeManager.createList() method.
63    """
64    dt=DateTimeManager()
65    return dt.createList(start, end, interval, listtype, formatstring)
66   
67   
68def getTimeBins(timelist):
69    """
70    Function wrapper around DateTimeManager.getTimeBins() method.
71    """
72    dt=DateTimeManager()
73    return dt.getTimeBins(timelist)
74
75
76def convertToSeconds(interval, unit):
77    """
78    Returns the number of seconds in the interval.
79    Note: year and month are approx values.
80    """
81    unit=unit.lower()
82    if unit[-1]=="s": unit=unit[:-1]
83    if unit=="year": 
84        secs=365*24*60*60*interval
85    elif unit=="month":
86        secs=30*24*60*60*interval
87    elif unit=="day":
88        secs=24*60*60*interval
89    elif unit=="hour":
90        secs=60*60*interval
91    elif unit=="minute":
92        secs=60*interval
93    elif unit=="second":
94        pass
95    else:
96        raise "Unit not recognised: %s" % unit
97    return secs
98
99
100def getAppropriateUnitAndInterval(value, unit):
101    """
102    Returns the appropriate time unit nearest to an integer for
103    time values that are fractions.
104    """
105    if value>=1:
106        return (unit, int(value))
107    nsecs=convertToSeconds(value, unit)
108    nsecs=int(nsecs)
109   
110    if nsecs<=1:
111        (u,i)=("second", 1)
112    elif nsecs<=60:
113        (u,i)=("second", nsecs)
114    elif nsecs<=(60*60):
115        (u,i)=("minute", nsecs/60)
116    elif nsecs<=(60*60*24):
117        (u,i)=("hour", nsecs/60/60)
118    elif nsecs<=(60*60*24*30):
119        (u,i)=("day", nsecs/60/60/24)
120    elif nsecs<=(60*60*24*365):
121        (u,i)=("month", nsecs/60/60/24/30)
122    else:
123        (u,i)=("year", nsecs/60/60/24/365)
124    return (u,i)
125
126
127def formatYear(fstring, dateTimeObj):
128    """
129    Copes with year outside Unix time epoch.
130    """
131    return fstring.replace("%Y", "%.4d" % dateTimeObj[0])
132
133
134class DateTimeManager:
135    """
136    Class to return lists of dates and times and allow adding and
137    subtracting of time intervals from time objects.
138    """
139   
140    # Class level parameters (do not change)
141    units={"year":"y ys yr yrs year years",
142           "month":"mon mons mnth mnths month months",
143           "day":"d ds dy dys day days",
144           "hour":"h hs hr hrs hour hours",
145           "minute":"min mins minute minutes",
146           "second":"s sc scs sec secs scnd scnds second seconds"}
147    positions=["year", "month", "day", "hour", "minute", "second"]
148    max=[99999, 13, None, 24, 60, 60] # These are the secs in mins etc...
149    min=[0, 1, 1, 0, 0, 0] 
150
151
152    def __init__(self, year=0, month=1, day=1, hour=0, minute=0, second=0):
153        """
154        Method to set up the instance formats and basic objects.
155        """
156        self.formats={"%Y":("%.4d","year"), "%y":("%.2d", "2dyear"), "%m":("%.2d","month"), "%d":("%.2d", "day"),
157             "%H":("%.2d", "hour"), "%M":("%.2d", "minute"), "%S":("%.2d", "second")}       
158        self.datetime=[year, month, day, hour, minute, second]
159        for i in range(0,6):
160            if type(self.datetime[i])!=types.IntType:
161                raise "Time components should be an integer: %s" % self.datetime[i]
162            max=DateTimeManager.max
163            max[2]=self.getDaysInMonth(month, year)
164            if self.datetime[i]>=max[i]:
165                raise "Time component '%s' must be less than limits: %s" % (self.datetime[i], str(max))
166        #print self.__repr__()
167
168
169    ##########################################
170    #
171    # __getattr__() method
172    #
173    ##########################################
174    def __getattr__(self, att):
175        if att in DateTimeManager.positions:
176            return self.datetime[DateTimeManager.positions.index(att)]
177        elif att=="datetime":
178            return self.__repr__()
179        return "Attribute not found: %s" % att
180
181
182    ##########################################
183    #
184    # __repr__() method
185    #
186    ##########################################
187    def __repr__(self):
188        return "%.4d-%.2d-%.2d %.2d:%.2d:%.2d" % tuple(self.datetime)
189       
190 
191    ##########################################
192    #
193    # __str__() method
194    #
195    ##########################################
196    def __str__(self):
197        return "%.4d-%.2d-%.2d %.2d:%.2d:%.2d" % tuple(self.datetime)
198
199
200    ##########################################
201    #
202    # add() method
203    #
204    ##########################################
205    def add(self, n, unit="hour"):
206        self.datetime=self._add(n, unit, self.datetime)
207        return self.__repr__()
208
209
210    ##########################################
211    #
212    # _add() method
213    #
214    ##########################################
215    def _add(self, n, unit="hour", itime=None):
216        unit=unit.lower()
217        if type(n)==types.TupleType:
218            increment=n
219        else:
220            for i in DateTimeManager.units.keys():
221                if i.find(unit)>-1 or DateTimeManager.units[i].find(unit)>-1:
222                    unit=i
223                    unitindex=DateTimeManager.positions.index(unit)
224                    increment=[0,0,0,0,0,0]
225                    increment[unitindex]=n
226                    break
227            itime=self._recalculate(increment, itime)
228        return itime
229
230
231    ##########################################
232    #
233    # _recalculate() method
234    #
235    ##########################################
236    def _recalculate(self, increment, itime):
237        max=DateTimeManager.max
238        min=DateTimeManager.min
239        for x in range(5,-1,-1):
240            if increment[x]==0:
241                continue
242            else:
243                if x==2:  # Calc days in month
244                    max[x]=self.getDaysInMonth(itime[1], itime[0])+1                 
245                itime[x]=itime[x]+increment[x]
246                if itime[x]>=max[x]:
247                    remainder=itime[x]%max[x]
248                    up_one=itime[x]/max[x]
249                    if remainder==0:
250                      itime[x]=min[x]
251                    else:
252                      itime[x]=remainder
253                    itime[x]
254                    increment[x-1]=increment[x-1]+up_one
255        #print itime
256        return itime
257
258
259    ##########################################
260    #
261    # sub() method
262    #
263    ##########################################
264    def sub(self, n, unit="hour"):
265        pass
266
267
268    ##########################################
269    #
270    # createList() method
271    #
272    ##########################################
273    def createList(self, start, end, interval=(6, "hour"), listtype="string", formatstring="%Y-%m-%d %H:%M:%S"):
274        if type(start)==types.StringType:
275            timepatt=("(\d{4})-(\d{1,2})-(\d{1,2})[ T](\d{1,2}):(\d{1,2}):(\d{1,2})")
276            startmatch=re.match(timepatt, start)
277            endmatch=re.match(timepatt, end)
278            if startmatch:
279                start=[]
280                for i in startmatch.groups():
281                    start.append(int(i))
282            if endmatch:
283                end=[]
284                for i in list(endmatch.groups()):
285                    end.append(int(i))
286        else:
287            filler=[0,1,1,0,0,0]
288            start=list(start)+filler[len(start):]
289            end=list(end)+filler[len(end):]
290            if type(start[0])!=type(1):
291                startlist=[]
292                endlist=[]
293                for i in range(6):
294                    startlist.append(int(start[i]))
295                    endlist.append(int(end[i]))
296                start=startlist
297                end=endlist
298           
299        now=start
300        rtlist=[]
301        end[-1]=end[-1]+1   # add one second to end so it catches it in while loop
302        while now<end:
303            #print "%.4d-%.2d-%.2d %.2d:%.2d:%.2d" % tuple(now), "%.4d-%.2d-%.2d %.2d:%.2d:%.2d" % tuple(end)
304            if listtype=="string":
305                rtlist.append(self.formatTime(formatstring, tuple(now)))
306            else:
307                rtlist.append(tuple(now))
308            now=self._add(interval[0], interval[1], now)
309        return rtlist
310   
311
312    ##########################################
313    #
314    # getDaysInMonth() method
315    #
316    ##########################################
317    def getDaysInMonth(self, month, year):
318        if month==2 and year%4==0:
319            return 29
320        else:
321            monthmap=(None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
322            return monthmap[int(month)]
323           
324           
325    ##########################################
326    #
327    # printtime() method
328    #
329    ##########################################
330    def printtime(self, formatstring="%Y-%m-%d %H:%M:%S", itime=None):
331        ftime=self.formatTime(formatstring, itime)
332        print ftime
333        return
334           
335           
336    ##########################################
337    #
338    # formatTime() method
339    #
340    ##########################################
341    def formatTime(self, formatstring="%Y-%m-%d %H:%M:%S", itime=None):
342        if itime==None: itime=self.datetime
343        #itimeDict={}
344        #count=0
345        #for k in ("year", "month", "day", "hour", "minute", "second"):   
346        #    itimeDict[k]=itime[count]
347        #    count=count+1         
348        #checkCount=0
349        formatstring=formatYear(formatstring, itime)
350        # Note the year has been got now so the rest uses a fake year to avoid error outside unix time
351        formatstring=time.strftime(formatstring, tuple([2000]+list((itime[1:]))+[0,1,0]))
352        #while formatstring.find("%")>-1:  # Keep in while loop just in case more than one occurrence of a field required
353        #    checkCount=checkCount+1
354        #    for f in self.formats.keys():
355        #        (formatter, item)=self.formats[f]
356        #       if type(item)==types.StringType:
357        #            replacer=formatter % itimeDict[item]
358        #       else:
359        #           replacer=formatter % (apply(item, (itime,)))
360        #       formatstring=formatstring.replace(f, replacer)
361        #    if checkCount>10: 
362        #       raise "Cannot interpret remaining characters in: '%s'" % (formatstring)         
363        return formatstring
364       
365    def getTimeBins(self, timelist):
366        """
367        Method to collect all available values of year, month, day etc into individual
368        lists for populating selection boxes.
369        """
370        # check type of input list
371        if type(timelist[0])!=tuple:
372            raise "Timelist items must be tuples."
373        # Create an empty list
374        nitems=len(timelist[0])
375        binlist=[]
376        for i in range(nitems):
377            binlist.append([])
378           
379        # Populate the return list   
380        for t in timelist:
381            for i in range(nitems):
382                if t[i] not in binlist[i]: binlist[i].append(t[i])
383               
384        # Make sure they are sorted
385        for i in range(nitems):
386            binlist[i].sort()
387           
388        return binlist
389       
390
391##############################################
392#
393# class UMTime
394#
395##############################################
396class UMTime(DateTimeManager):
397
398    ##########################################
399    #
400    # __init__() method
401    #
402    ##########################################
403    def __init__(self, year=0, month=1, day=1, hour=0, minute=0, second=0):
404        DateTimeManager.__init__(self, year, month, day, hour, minute, second)
405        self.formats["%umyear"]=("%.4d_%s", self.getUMYear)   
406
407
408    ##########################################
409    #
410    # getUMYear() method
411    #
412    ##########################################
413    def getUMYear(self, itime):
414        umyear=itime[0]+1800
415        return (umyear, "holiday") 
416 
417       
418       
419                   
420                   
421
422
423   
Note: See TracBrowser for help on using the repository browser.