Coverage for astrocalc/times/conversions.py : 85%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/local/bin/python
2# encoding: utf-8
3"""
4*Convert times between various epochs and units*
6:Author:
7 David Young
8"""
9from __future__ import division
10from past.utils import old_div
11from builtins import object
12import sys
13import os
14os.environ['TERM'] = 'vt100'
15from fundamentals import tools
17class conversions(object):
18 """
19 *The worker class for the conversions module*
21 **Key Arguments**
23 - ``log`` -- logger
24 - ``settings`` -- the settings dictionary
27 **Usage**
29 .. todo::
31 - add usage info
32 - create a sublime snippet for usage
33 - add mjd_to_date
34 - add decimal_day_to_day_hour_min_sec
35 - add date_to_mjd
36 - convert all functions in __init__ to modules
38 ```python
39 usage code
40 ```
42 """
43 # Initialisation
45 def __init__(
46 self,
47 log,
48 settings=False,
49 ):
50 self.log = log
51 log.debug("instansiating a new 'conversions' object")
52 self.settings = settings
53 # xt-self-arg-tmpx
55 return None
57 def get(self):
58 """
59 *get the conversions object*
61 **Return**
63 - ``conversions``
66 .. todo::
68 - @review: when complete, clean get method
69 - @review: when complete add logging
70 """
71 self.log.debug('starting the ``get`` method')
73 conversions = None
75 self.log.debug('completed the ``get`` method')
76 return conversions
78 def ut_datetime_to_mjd(
79 self,
80 utDatetime):
81 """*ut datetime to mjd*
83 If the date given has no time associated with it (e.g. ``20160426``), then the datetime assumed is ``20160426 00:00:00.0``.
85 Precision should be respected.
87 **Key Arguments**
89 - ``utDatetime`` -- UT datetime. Can accept various formats e.g. ``201604261444``, ``20160426``, ``20160426144444.5452``, ``2016-04-26 14:44:44.234``, ``20160426 14h44m44.432s``
92 **Return**
94 - ``mjd`` -- the MJD
97 .. todo ::
99 - replace getMJDFromSqlDate in all code
101 **Usage**
103 ```python
104 from astrocalc.times import conversions
105 converter = conversions(
106 log=log
107 )
108 mjd = converter.ut_datetime_to_mjd(utDatetime="20160426t1446")
109 print(mjd)
111 # OUT: 57504.6153
113 mjd = converter.ut_datetime_to_mjd(utDatetime="2016-04-26 14:44:44.234")
114 print(mjd)
116 # OUT: 57504.61440
117 ```
119 """
120 self.log.debug('starting the ``ut_datetime_to_mjd`` method')
122 import time
123 import re
124 mjd = None
126 # TRIM WHITESPACE FROM AROUND STRING
127 utDatetime = utDatetime.strip()
129 # DATETIME REGEX
130 matchObject = re.match(
131 r'^(?P<year>\d{4})\D?(?P<month>(0\d|1[0-2]))\D?(?P<day>([0-2]\d|3[0-1])(\.\d+)?)(\D?(?P<hours>([0-1]\d|2[0-3]))\D?(?P<minutes>\d{2})(\D?(?P<seconds>\d{2}(\.\d*?)?))?)?s?$', utDatetime)
133 # RETURN ERROR IF REGEX NOT MATCHED
134 if not matchObject:
135 self.log.error(
136 'UT Datetime is not in a recognised format. Input value was `%(utDatetime)s`' % locals())
137 raise IOError(
138 'UT Datetime is not in a recognised format. Input value was `%(utDatetime)s`' % locals())
140 year = matchObject.group("year")
141 month = matchObject.group("month")
142 day = matchObject.group("day")
143 hours = matchObject.group("hours")
144 minutes = matchObject.group("minutes")
145 seconds = matchObject.group("seconds")
147 # CLEAN NUMBERS AND SET OUTPUT PRECISION
148 if "." in day:
149 fhours = (float(day) - int(float(day))) * 24
150 hours = int(fhours)
151 fminutes = (fhours - hours) * 60
152 minutes = int(fminutes)
153 seconds = fhours - minutes
154 precision = len(repr(day).split(".")[-1])
155 elif not hours:
156 hours = "00"
157 minutes = "00"
158 seconds = "00"
159 precision = 1
160 elif not seconds:
161 seconds = "00"
162 # PRECISION TO NEAREST MIN i.e. 0.000694444 DAYS
163 precision = 4
164 else:
165 if "." not in seconds:
166 precision = 5
167 else:
168 decLen = len(seconds.split(".")[-1])
169 precision = 5 + decLen
171 # CONVERT VALUES TO FLOAT
172 seconds = float(seconds)
173 year = float(year)
174 month = float(month)
175 day = float(day)
176 hours = float(hours)
177 minutes = float(minutes)
179 # DETERMINE EXTRA TIME (SMALLER THAN A SEC)
180 extraTime = 0.
181 if "." in repr(seconds):
182 extraTime = old_div(float("." + repr(seconds).split(".")
183 [-1]), (24. * 60. * 60.))
185 # CONVERT TO UNIXTIME THEN MJD
186 t = (int(year), int(month), int(day), int(hours),
187 int(minutes), int(seconds), 0, 0, 0)
188 unixtime = int(time.mktime(t))
189 mjd = (old_div(unixtime, 86400.0) - 2400000.5 + 2440587.5) + extraTime
191 mjd = "%0.*f" % (precision, mjd)
193 self.log.debug('completed the ``ut_datetime_to_mjd`` method')
194 return mjd
196 def mjd_to_ut_datetime(
197 self,
198 mjd,
199 sqlDate=False,
200 datetimeObject=False):
201 """*mjd to ut datetime*
203 Precision should be respected.
205 **Key Arguments**
207 - ``mjd`` -- time in MJD.
208 - ``sqlDate`` -- add a 'T' between date and time instead of space
209 - ``datetimeObject`` -- return a datetime object instead of a string. Default *False*
212 .. todo::
214 - replace getDateFromMJD in all code
215 - replace getSQLDateFromMJD in all code
217 **Return**
219 - ``utDatetime`` - the UT datetime in string format
222 **Usage**
224 ```python
225 from astrocalc.times import conversions
226 converter = conversions(
227 log=log
228 )
229 utDate = converter.mjd_to_ut_datetime(
230 mjd=57504.61577585013
231 )
232 print(utDate)
234 # OUT: 2016-04-26 14:46:43.033
236 utDate = converter.mjd_to_ut_datetime(
237 mjd=57504.61577585013,
238 sqlDate=True
239 )
240 print(utDate)
242 # OUT: 2016-04-26T14:46:43.033
243 ```
245 """
246 self.log.debug('starting the ``mjd_to_ut_datetime`` method')
248 from datetime import datetime
250 # CONVERT TO UNIXTIME
251 unixtime = (float(mjd) + 2400000.5 - 2440587.5) * 86400.0
252 theDate = datetime.utcfromtimestamp(unixtime)
254 if datetimeObject == False:
255 # DETERMINE PRECISION
256 strmjd = repr(mjd)
257 if "." not in strmjd:
258 precisionUnit = "day"
259 precision = 0
260 utDatetime = theDate.strftime("%Y-%m-%d")
261 else:
262 lenDec = len(strmjd.split(".")[-1])
263 if lenDec < 2:
264 precisionUnit = "day"
265 precision = 0
266 utDatetime = theDate.strftime("%Y-%m-%d")
267 elif lenDec < 3:
268 precisionUnit = "hour"
269 precision = 0
270 utDatetime = theDate.strftime("%Y-%m-%d")
271 elif lenDec < 5:
272 precisionUnit = "minute"
273 precision = 0
274 utDatetime = theDate.strftime("%Y-%m-%d %H:%M")
275 else:
276 precisionUnit = "second"
277 precision = lenDec - 5
278 if precision > 3:
279 precision = 3
280 secs = float(theDate.strftime("%S.%f"))
281 secs = "%02.*f" % (precision, secs)
282 utDatetime = theDate.strftime("%Y-%m-%d %H:%M:") + secs
284 if sqlDate:
285 utDatetime = utDatetime.replace(" ", "T")
286 else:
287 utDatetime = theDate
289 self.log.debug('completed the ``mjd_to_ut_datetime`` method')
290 return utDatetime
292 def decimal_day_to_day_hour_min_sec(
293 self,
294 daysFloat):
295 """*Convert a day from decimal format to hours mins and sec*
297 Precision should be respected.
299 **Key Arguments**
301 - ``daysFloat`` -- the day as a decimal.
304 **Return**
306 - ``daysInt`` -- day as an integer
307 - ``hoursInt`` -- hour as an integer (None if input precsion too low)
308 - ``minsInt`` -- mins as an integer (None if input precsion too low)
309 - ``secFloat`` -- secs as a float (None if input precsion too low)
312 **Usage**
314 .. todo::
316 - replace `decimal_day_to_day_hour_min_sec` in all other code
318 ```python
319 from astrocalc.times import conversions
320 converter = conversions(
321 log=log
322 )
323 daysInt, hoursInt, minsInt, secFloat = converter.decimal_day_to_day_hour_min_sec(
324 daysFloat=24.2453
325 )
326 print(daysInt, hoursInt, minsInt, secFloat)
328 # OUTPUT: 24, 5, 53, None
330 daysInt, hoursInt, minsInt, secFloat = converter.decimal_day_to_day_hour_min_sec(
331 daysFloat=24.1232435454
332 )
333 print("%(daysInt)s days, %(hoursInt)s hours, %(minsInt)s mins, %(secFloat)s sec" % locals())
335 # OUTPUT: 24 days, 2 hours, 57 mins, 28.242 sec
336 ```
338 """
339 self.log.debug(
340 'completed the ````decimal_day_to_day_hour_min_sec`` method')
342 daysInt = int(daysFloat)
343 hoursFloat = (daysFloat - daysInt) * 24.
344 hoursInt = int(hoursFloat)
345 minsFloat = (hoursFloat - hoursInt) * 60.
346 minsInt = int(minsFloat)
347 secFloat = (minsFloat - minsInt) * 60.
349 # DETERMINE PRECISION
350 strday = repr(daysFloat)
351 if "." not in strday:
352 precisionUnit = "day"
353 precision = 0
354 hoursInt = None
355 minsInt = None
356 secFloat = None
357 else:
358 lenDec = len(strday.split(".")[-1])
359 if lenDec < 2:
360 precisionUnit = "day"
361 precision = 0
362 hoursInt = None
363 minsInt = None
364 secFloat = None
365 elif lenDec < 3:
366 precisionUnit = "hour"
367 precision = 0
368 minsInt = None
369 secFloat = None
370 elif lenDec < 5:
371 precisionUnit = "minute"
372 precision = 0
373 secFloat = None
374 else:
375 precisionUnit = "second"
376 precision = lenDec - 5
377 if precision > 3:
378 precision = 3
379 secFloat = "%02.*f" % (precision, secFloat)
381 self.log.debug(
382 'completed the ``decimal_day_to_day_hour_min_sec`` method')
383 return daysInt, hoursInt, minsInt, secFloat
385 # use the tab-trigger below for new method
386 # xt-class-method