#!/usr/local/bin/python
# encoding: utf-8
"""
*Convert times between various epochs and units*
Author
: David Young
"""
from __future__ import division
from past.utils import old_div
from builtins import object
import sys
import os
os.environ['TERM'] = 'vt100'
[docs]
class conversions(object):
"""
*The worker class for the conversions module*
**Key Arguments**
- ``log`` -- logger
- ``settings`` -- the settings dictionary
**Usage**
.. todo::
- add usage info
- create a sublime snippet for usage
- add mjd_to_date
- add decimal_day_to_day_hour_min_sec
- add date_to_mjd
- convert all functions in __init__ to modules
```python
usage code
```
"""
# Initialisation
def __init__(
self,
log,
settings=False,
):
self.log = log
log.debug("instansiating a new 'conversions' object")
self.settings = settings
# xt-self-arg-tmpx
return None
[docs]
def get(self):
"""
*get the conversions object*
**Return**
- ``conversions``
.. todo::
- @review: when complete, clean get method
- @review: when complete add logging
"""
self.log.debug('starting the ``get`` method')
conversions = None
self.log.debug('completed the ``get`` method')
return conversions
[docs]
def ut_datetime_to_mjd(
self,
utDatetime):
"""*ut datetime to mjd*
If the date given has no time associated with it (e.g. ``20160426``), then the datetime assumed is ``20160426 00:00:00.0``.
Precision should be respected.
**Key Arguments**
- ``utDatetime`` -- UT datetime. Can accept various formats e.g. ``201604261444``, ``20160426``, ``20160426144444.5452``, ``2016-04-26 14:44:44.234``, ``20160426 14h44m44.432s``
**Return**
- ``mjd`` -- the MJD
.. todo ::
- replace getMJDFromSqlDate in all code
**Usage**
```python
from astrocalc.times import conversions
converter = conversions(
log=log
)
mjd = converter.ut_datetime_to_mjd(utDatetime="20160426t1446")
print(mjd)
# OUT: 57504.6153
mjd = converter.ut_datetime_to_mjd(utDatetime="2016-04-26 14:44:44.234")
print(mjd)
# OUT: 57504.61440
```
"""
self.log.debug('starting the ``ut_datetime_to_mjd`` method')
import time
import re
mjd = None
# TRIM WHITESPACE FROM AROUND STRING
utDatetime = utDatetime.strip()
# DATETIME REGEX
matchObject = re.match(
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)
# RETURN ERROR IF REGEX NOT MATCHED
if not matchObject:
self.log.error(
'UT Datetime is not in a recognised format. Input value was `%(utDatetime)s`' % locals())
raise IOError(
'UT Datetime is not in a recognised format. Input value was `%(utDatetime)s`' % locals())
year = matchObject.group("year")
month = matchObject.group("month")
day = matchObject.group("day")
hours = matchObject.group("hours")
minutes = matchObject.group("minutes")
seconds = matchObject.group("seconds")
# CLEAN NUMBERS AND SET OUTPUT PRECISION
if "." in day:
fhours = (float(day) - int(float(day))) * 24
hours = int(fhours)
fminutes = (fhours - hours) * 60
minutes = int(fminutes)
seconds = fhours - minutes
precision = len(repr(day).split(".")[-1])
elif not hours:
hours = "00"
minutes = "00"
seconds = "00"
precision = 1
elif not seconds:
seconds = "00"
# PRECISION TO NEAREST MIN i.e. 0.000694444 DAYS
precision = 4
else:
if "." not in seconds:
precision = 5
else:
decLen = len(seconds.split(".")[-1])
precision = 5 + decLen
# CONVERT VALUES TO FLOAT
seconds = float(seconds)
year = float(year)
month = float(month)
day = float(day)
hours = float(hours)
minutes = float(minutes)
# DETERMINE EXTRA TIME (SMALLER THAN A SEC)
extraTime = 0.
if "." in repr(seconds):
extraTime = old_div(float("." + repr(seconds).split(".")
[-1]), (24. * 60. * 60.))
# CONVERT TO UNIXTIME THEN MJD
t = (int(year), int(month), int(day), int(hours),
int(minutes), int(seconds), 0, 0, 0)
unixtime = int(time.mktime(t))
mjd = (old_div(unixtime, 86400.0) - 2400000.5 + 2440587.5) + extraTime
mjd = "%0.*f" % (precision, mjd)
self.log.debug('completed the ``ut_datetime_to_mjd`` method')
return mjd
[docs]
def mjd_to_ut_datetime(
self,
mjd,
sqlDate=False,
datetimeObject=False):
"""*mjd to ut datetime*
Precision should be respected.
**Key Arguments**
- ``mjd`` -- time in MJD.
- ``sqlDate`` -- add a 'T' between date and time instead of space
- ``datetimeObject`` -- return a datetime object instead of a string. Default *False*
.. todo::
- replace getDateFromMJD in all code
- replace getSQLDateFromMJD in all code
**Return**
- ``utDatetime`` - the UT datetime in string format
**Usage**
```python
from astrocalc.times import conversions
converter = conversions(
log=log
)
utDate = converter.mjd_to_ut_datetime(
mjd=57504.61577585013
)
print(utDate)
# OUT: 2016-04-26 14:46:43.033
utDate = converter.mjd_to_ut_datetime(
mjd=57504.61577585013,
sqlDate=True
)
print(utDate)
# OUT: 2016-04-26T14:46:43.033
```
"""
self.log.debug('starting the ``mjd_to_ut_datetime`` method')
from datetime import datetime
# CONVERT TO UNIXTIME
unixtime = (float(mjd) + 2400000.5 - 2440587.5) * 86400.0
theDate = datetime.utcfromtimestamp(unixtime)
if datetimeObject == False:
# DETERMINE PRECISION
strmjd = repr(mjd)
if "." not in strmjd:
precisionUnit = "day"
precision = 0
utDatetime = theDate.strftime("%Y-%m-%d")
else:
lenDec = len(strmjd.split(".")[-1])
if lenDec < 2:
precisionUnit = "day"
precision = 0
utDatetime = theDate.strftime("%Y-%m-%d")
elif lenDec < 3:
precisionUnit = "hour"
precision = 0
utDatetime = theDate.strftime("%Y-%m-%d")
elif lenDec < 5:
precisionUnit = "minute"
precision = 0
utDatetime = theDate.strftime("%Y-%m-%d %H:%M")
else:
precisionUnit = "second"
precision = lenDec - 5
if precision > 3:
precision = 3
secs = float(theDate.strftime("%S.%f"))
secs = "%02.*f" % (precision, secs)
utDatetime = theDate.strftime("%Y-%m-%d %H:%M:") + secs
if sqlDate:
utDatetime = utDatetime.replace(" ", "T")
else:
utDatetime = theDate
self.log.debug('completed the ``mjd_to_ut_datetime`` method')
return utDatetime
[docs]
def decimal_day_to_day_hour_min_sec(
self,
daysFloat):
"""*Convert a day from decimal format to hours mins and sec*
Precision should be respected.
**Key Arguments**
- ``daysFloat`` -- the day as a decimal.
**Return**
- ``daysInt`` -- day as an integer
- ``hoursInt`` -- hour as an integer (None if input precsion too low)
- ``minsInt`` -- mins as an integer (None if input precsion too low)
- ``secFloat`` -- secs as a float (None if input precsion too low)
**Usage**
.. todo::
- replace `decimal_day_to_day_hour_min_sec` in all other code
```python
from astrocalc.times import conversions
converter = conversions(
log=log
)
daysInt, hoursInt, minsInt, secFloat = converter.decimal_day_to_day_hour_min_sec(
daysFloat=24.2453
)
print(daysInt, hoursInt, minsInt, secFloat)
# OUTPUT: 24, 5, 53, None
daysInt, hoursInt, minsInt, secFloat = converter.decimal_day_to_day_hour_min_sec(
daysFloat=24.1232435454
)
print("%(daysInt)s days, %(hoursInt)s hours, %(minsInt)s mins, %(secFloat)s sec" % locals())
# OUTPUT: 24 days, 2 hours, 57 mins, 28.242 sec
```
"""
self.log.debug(
'completed the ````decimal_day_to_day_hour_min_sec`` method')
daysInt = int(daysFloat)
hoursFloat = (daysFloat - daysInt) * 24.
hoursInt = int(hoursFloat)
minsFloat = (hoursFloat - hoursInt) * 60.
minsInt = int(minsFloat)
secFloat = (minsFloat - minsInt) * 60.
# DETERMINE PRECISION
strday = repr(daysFloat)
if "." not in strday:
precisionUnit = "day"
precision = 0
hoursInt = None
minsInt = None
secFloat = None
else:
lenDec = len(strday.split(".")[-1])
if lenDec < 2:
precisionUnit = "day"
precision = 0
hoursInt = None
minsInt = None
secFloat = None
elif lenDec < 3:
precisionUnit = "hour"
precision = 0
minsInt = None
secFloat = None
elif lenDec < 5:
precisionUnit = "minute"
precision = 0
secFloat = None
else:
precisionUnit = "second"
precision = lenDec - 5
if precision > 3:
precision = 3
secFloat = "%02.*f" % (precision, secFloat)
self.log.debug(
'completed the ``decimal_day_to_day_hour_min_sec`` method')
return daysInt, hoursInt, minsInt, secFloat
# use the tab-trigger below for new method
# xt-class-method