NCCOOS Trac Projects: Top | Web | Platforms | Processing | Viz | Sprints | Sandbox | (Wind)

root/raw2proc/trunk/raw2proc/procutil.py

Revision 118 (checked in by haines, 16 years ago)

Added new mod timestamp

Line 
1 #!/usr/bin/env python
2 # Last modified:  Time-stamp: <2008-02-19 15:04:00 jcleary>
3 """Utilities to help data processing
4
5    Mostly time functions right now
6
7    TO DO:
8    check_configs()
9    unit conversions (udunits?)
10 """
11
12 __version__ = "v0.1"
13 __author__ = "Sara Haines <sara_haines@unc.edu>"
14
15 from datetime import datetime, timedelta, tzinfo
16 from dateutil.tz import tzlocal, tzutc
17 import time
18
19 def check_configs():
20     """Test config files for comformnity
21
22     check either one or all for a platform
23    
24     id in filename == platform.id
25     datetime in filename <= platform.config_start_date
26        (close in time usually the same day
27     also platform.config_start_date < platform.config_end_date
28        (there needs to be some time that the platform was operational)
29     test existence of specific structural elements (platform info and sensor info)
30     and specific fields for both platform and sensor
31     verify that for each platform_info['packages'] there is sensor_info and same id
32       for pi['packages'][0] in si.keys()
33       pi['packages'][0] == si['adcp']['id']
34     bounds on data in fields
35     show difference between two consecutive configs?
36     pretty print to screen of dictionary info for platform and sensor info
37    
38         cn = os.path.splitext(os.path.basename(config))[0]
39         cndt = filt_datetime(os.path.basename(config))[0]
40         pi = get_config(cn+'.platform_info')
41         if pi['config_start_date']:
42             config_start_dt = filt_datetime(pi['config_start_date'])[0]
43         elif pi['config_start_date'] == None:
44             config_start_dt = now_dt
45         if pi['config_end_date']:
46             config_end_dt = filt_datetime(pi['config_end_date'])[0]
47         elif pi['config_end_date'] == None:
48             config_end_dt = now_dt
49
50         print cn + ' -----------------'
51         print cndt
52         print config_start_dt
53         print config_end_dt
54         print now_dt
55         print 'file date ok? ' + str(cndt <= config_start_dt)
56         print 'operation date ok? ' + str(config_start_dt < config_end_dt)
57     """
58
59 def dt2es(dt):
60     """Convert datetime object to epoch seconds (es) as seconds since Jan-01-1970 """
61     # microseconds of timedelta object not used
62     delta = dt - datetime(1970,1,1,0,0,0)
63     es = delta.days*24*60*60 + delta.seconds
64     return es
65
66 def es2dt(es):
67     """ Convert epoch seconds (es) to datetime object"""
68     dt = datetime(*time.gmtime(es)[0:6])
69     return dt
70
71 def find_months(year, month=1):
72     """Find which months to process
73
74     Since data are in subdirectories based on months determine
75     previous, current, and next month to look in directories for data
76     of the current month or month to process.
77
78     :Parameters:
79         year : int value or str 'yyyy_mm'
80         month : int value
81
82     :Returns:
83         which_months : tuple of 3 datetime objects
84              (prev_month, current_month, next_month)
85
86     Examples
87     --------
88     >>> find_months(2007, 2)
89     >>> find_months('2007_02')
90    
91     """
92     if type(year) == int and type(month) == int :
93         dt = datetime(year, month, day=1)
94         this_month = dt
95     elif type(year) == str :
96         dt = filt_datetime(year)[0]
97         this_month = dt
98     #
99     if dt.month == 1: # if January
100         prev_month = datetime(dt.year-1, month=12, day=1) # Dec
101         next_month = datetime(dt.year, dt.month+1, day=1) # Feb
102     elif dt.month == 12: # if December
103         prev_month = datetime(dt.year, dt.month-1, day=1) # Nov
104         next_month = datetime(dt.year+1, month=1, day=1)  # Jan
105     else:
106         prev_month = datetime(dt.year, dt.month-1, day=1)
107         next_month = datetime(dt.year, dt.month+1, day=1)
108     #
109     return (prev_month, this_month, next_month)
110
111 def this_month():
112     """Return this month (GMT) as formatted string (yyyy_mm) """
113     this_month_str = "%4d_%02d" % time.gmtime()[0:2]
114     return this_month_str
115
116 def scanf_datetime(ts, fmt='%Y-%m-%dT%H:%M:%S'):
117     """Convert string representing date and time to datetime object"""
118     # default string format follows convention YYYY-MM-DDThh:mm:ss
119    
120     t = time.strptime(ts, fmt)
121     # the '*' operator unpacks the tuple, producing the argument list.
122     dt = datetime(*t[0:6])
123     return dt
124
125 def filt_datetime(input_string, remove_ext=True):
126     """
127     Following the template, (YY)YYMMDDhhmmss
128     and versions with of this with decreasing time precision,
129     find the most precise, reasonable string match and
130     return its datetime object.
131     """
132
133     # remove any trailing filename extension
134     from os.path import splitext
135     import re
136     if remove_ext:
137         (s, e) = splitext(input_string)
138         input_string = s
139    
140     # YYYYMMDDhhmmss and should handle most cases of the stamp
141     # other forms this should pass
142     # YY_MM_DD_hh:mm:ss
143     # YYYY_MM_DD_hh:mm:ss
144     # YYYY,MM,DD,hh,mm,ss
145     # YY,MM,DD,hh,mm,ss
146
147     case1_regex = r"""
148     # case 1: (YY)YYMMDDhhmmss
149     (\d{4}|\d{2})     # 2- or 4-digit YEAR (e.g. '07' or '2007')
150     \D?               # optional 1 character non-digit separator (e.g. ' ' or '-')
151     (\d{2})           # 2-digit MONTH (e.g. '12')
152     \D?               # optional 1 character non-digit separator
153     (\d{2})           # 2-digit DAY of month (e.g. '10')
154     \D?               # optional 1 character non-digit separator (e.g. ' ' or 'T')
155     (\d{2})           # 2-digit HOUR (e.g. '10')
156     \D?               # optional 1 character non-digit separator (e.g. ' ' or ':')
157     (\d{2})           # 2-digit MINUTE (e.g. '10')
158     \D?               # optional 1 character non-digit separator (e.g. ' ' or ':')
159     (\d{2})           # 2-digit SECOND (e.g. '10')
160     """
161
162     case2_regex = r"""
163     # case 2: (YY)YYMMDDhhmm (no seconds)
164     (\d{4}|\d{2})     # 2- or 4-digit YEAR
165     \D?               # optional 1 character non-digit separator (e.g. ' ' or '-')
166     (\d{2})           # 2-digit MONTH
167     \D?               # optional 1 character non-digit separator
168     (\d{2})           # 2-digit DAY
169     \D?               # optional 1 character non-digit separator (e.g. ' ' or 'T')
170     (\d{2})           # 2-digit HOUR
171     \D?               # optional 1 character non-digit separator (e.g. ' ' or ':')
172     (\d{2})           # 2-digit MINUTE
173     """
174
175     case3_regex = r"""
176     # case 3: (YY)YYMMDDhh (no seconds, no minutes)
177     (\d{4}|\d{2})     # 2- or 4-digit YEAR
178     \D?               # optional 1 character non-digit separator (e.g. ' ' or '-')
179     (\d{2})           # 2-digit MONTH
180     \D?               # optional 1 character non-digit separator
181     (\d{2})           # 2-digit DAY
182     \D?               # optional 1 character non-digit separator (e.g. ' ' or 'T')
183     (\d{2})           # 2-digit HOUR
184     """
185
186     case4_regex = r"""
187     # case 4: (YY)YYMMDD (no time values, just date)
188     (\d{4}|\d{2})     # 2- or 4-digit YEAR
189     \D?               # optional 1 character non-digit separator (e.g. ' ' or '-')
190     (\d{2})           # 2-digit MONTH
191     \D?               # optional 1 character non-digit separator
192     (\d{2})           # 2-digit DAY
193     """
194
195     case5_regex = r"""
196     # case 5: (YY)YYMM (no time values, just month year)
197     (\d{4}|\d{2})     # 2- or 4-digit YEAR
198     \D?               # optional 1 character non-digit separator (e.g. ' ' or '-')
199     (\d{2})           # 2-digit MONTH
200     """
201
202     ##  Verbose regular expressions require use of re.VERBOSE flag.
203     ##  so we can use multiline regexp
204
205     # cases are ordered from precise to more coarse resolution of time
206     cases = [case1_regex, case2_regex, case3_regex, case4_regex, case5_regex]
207     patterns = [re.compile(c, re.VERBOSE) for c in cases]
208     matches = [p.search(input_string) for p in patterns]
209
210     # for testing, try to computer datetime objects
211     # just because there is a match does not mean it makes sense
212     for ind in range(len(matches)):
213         if bool(matches[ind]):
214             # print matches[ind].groups()
215             bits = matches[ind].groups()
216             values = [int(yi) for yi in bits]
217             # check for 2-digit year
218             if values[0] < 50:
219                 values[0] += 2000
220             elif values[0]>=50 and values[0]<100:
221                 values[0] += 1900
222             #
223             # we must have at least 3 arg input to datetime
224             if len(values)==1:
225                 values.extend([1,1]) # add First of January
226             elif len(values)==2:
227                 values.extend([1]) # add first day of month
228
229             #
230             # compute dt
231             try:
232                 dt = datetime(*values)
233             except ValueError, e:
234                 # value error if something not valid for datetime
235                 # e.g. month 1...12, something parsed wrong
236                 dt = None
237             else:
238                 # absolute difference in days from now (UTC)
239                 z = dt - datetime.utcnow()
240                 daysdiff = abs(z.days)
241                 # if this date unreasonable (>10 years*365), throw it out
242                 # something parsed wrong
243                 if daysdiff > 3650:
244                     dt = None               
245         else:
246             dt = None
247
248         # place datetime object or None within sequence of matches
249         matches[ind] = dt
250
251     # find the first (most precise) date match since there might be more than
252     # as we searched more coarse templates, but now we have thrown out
253    
254     b = [bool(x) for x in matches]
255     try:
256         ind = b.index(True)
257     except ValueError, e:
258         print 'filt_datetime: No date found in ', input_string
259         dt = None
260     else:
261        dt = matches[ind]
262        return dt,ind
263
264 def display_time_diff(diff):
265     """Display time difference in HH:MM:DD using number weeks (W)
266     and days (D) if necessary"""
267     # weeks, days = divmod(diff.days, 7)
268     days = diff.days
269     minutes, seconds = divmod(diff.seconds, 60)
270     hours, minutes = divmod(minutes, 60)   
271     # if (weeks>2 and days>0):
272     #    str = "%d Weeks, %d Days %02d:%02d" % (days, hours, minutes)
273     if (days==1):
274         str = "%02d:%02d" % (24+hours, minutes)
275     elif (days>1):
276         str = "%d Days %02d:%02d" % (days, hours, minutes)
277     else:
278         str = "%02d:%02d" % (hours, minutes)
279     return str
280
281 # unit conversions
282 def meters2feet(meters):
283     """Convert meters to feet: <feet> = <meters>*3.28084 """
284     return meters*3.28084
285        
286 #
Note: See TracBrowser for help on using the browser.