"""Ladybug datetime."""
# coding=utf-8
from datetime import datetime
[docs]class DateTime(datetime):
"""Create Ladybug Date time.
Args:
month: A value for month between 1-12 (Defualt: 1).
day: A value for day between 1-31 (Defualt: 1).
hour: A value for hour between 0-23 (Defualt: 0).
minute: A value for month between 0-59 (Defualt: 0).
leap_year: A boolean to indicate if datetime is for a leap year
(Default: False).
"""
__slots__ = ()
def __new__(cls, month=1, day=1, hour=0, minute=0, leap_year=False):
"""Create Ladybug datetime.
Args:
month: A value for month between 1-12 (Defualt: 1).
day: A value for day between 1-31 (Defualt: 1).
hour: A value for hour between 0-23 (Defualt: 0).
minute: A value for month between 0-59 (Defualt: 0).
leap_year: A boolean to indicate if datetime is for a leap year
(Default: False).
"""
year = 2016 if leap_year else 2017
hour, minute = cls._calculate_hour_and_minute(hour + minute / 60.0)
try:
return datetime.__new__(cls, year, month, day, hour, minute)
except ValueError as e:
raise ValueError("{}:\n\t({}/{}@{}:{})(m/d@h:m)".format(
e, month, day, hour, minute
))
[docs] @classmethod
def from_json(cls, data):
"""Creat datetime from a dictionary.
Args:
data: {
'month': A value for month between 1-12. (Defualt: 1)
'day': A value for day between 1-31. (Defualt: 1)
'hour': A value for hour between 0-23. (Defualt: 0)
'minute': A value for month between 0-59. (Defualt: 0)
}
"""
if 'month' not in data:
data['month'] = 1
if 'day' not in data:
data['day'] = 1
if 'hour' not in data:
data['hour'] = 0
if 'minute' not in data:
data['minute'] = 0
if 'year' not in data:
data['year'] = 2017
leap_year = True if int(data['year']) == 2016 else False
return cls(data['month'], data['day'], data['hour'], data['minute'], leap_year)
[docs] @classmethod
def from_hoy(cls, hoy, leap_year=False):
"""Create Ladybug Datetime from an hour of the year.
Args:
hoy: A float value 0 <= and < 8760
"""
return cls.from_moy(round(hoy * 60), leap_year)
[docs] @classmethod
def from_moy(cls, moy, leap_year=False):
"""Create Ladybug Datetime from a minute of the year.
Args:
moy: An integer value 0 <= and < 525600
"""
if not leap_year:
num_of_minutes_until_month = (0, 44640, 84960, 129600, 172800, 217440,
260640, 305280, 349920, 393120, 437760,
480960, 525600)
else:
num_of_minutes_until_month = (0, 44640, 84960 + 1440, 129600 + 1440,
172800 + 1440, 217440 + 1440, 260640 + 1440,
305280 + 1440, 349920 + 1440, 393120 + 1440,
437760 + 1440, 480960 + 1440, 525600 + 1440)
# find month
for monthCount in range(12):
if int(moy) < num_of_minutes_until_month[monthCount + 1]:
month = monthCount + 1
break
try:
day = int((moy - num_of_minutes_until_month[month - 1]) / (60 * 24)) + 1
except UnboundLocalError:
raise ValueError(
"moy must be positive and smaller than 525600. Invalid input %d" % (moy)
)
else:
hour = int((moy / 60) % 24)
minute = int(moy % 60)
return cls(month, day, hour, minute, leap_year)
[docs] @classmethod
def from_date_time_string(cls, datetime_string, leap_year=False):
"""Create Ladybug DateTime from a DateTime string.
Usage:
dt = DateTime.from_date_time_string("31 Dec 12:00")
"""
dt = datetime.strptime(datetime_string, '%d %b %H:%M')
return cls(dt.month, dt.day, dt.hour, dt.minute, leap_year)
@property
def isDateTime(self):
"""Check if data is ladybug data."""
return True
@property
def doy(self):
"""Calculate day of the year for this date time."""
return self.timetuple().tm_yday
@property
def hoy(self):
"""Calculate hour of the year for this date time."""
return (self.doy - 1) * 24 + self.float_hour
@property
def moy(self):
"""Calculate minute of the year for this date time."""
return self.int_hoy * 60 + self.minute # minute of the year
@property
def float_hour(self):
"""Get hour and minute as a float value (e.g. 6.25 for 6:15)."""
return self.hour + self.minute / 60.0
@property
def int_hoy(self):
"""Calculate hour of the year for this date time as an integer.
This output assumes the minute is 0.
"""
return (self.doy - 1) * 24 + self.hour
@staticmethod
def _calculate_hour_and_minute(float_hour):
"""Calculate hour and minutes as integers from a float hour."""
hour, minute = int(float_hour), int(round((float_hour - int(float_hour)) * 60))
if minute == 60:
return hour + 1, 0
else:
return hour, minute
[docs] def add_minute(self, minute):
"""Create a new DateTime after the minutes are added.
Args:
minute: An integer value for minutes.
"""
_moy = self.moy + int(minute)
return self.__class__.from_moy(_moy)
[docs] def sub_minute(self, minute):
"""Create a new DateTime after the minutes are subtracted.
Args:
minute: An integer value for the number of minutes.
"""
return self.add_minute(-minute)
[docs] def add_hour(self, hour):
"""Create a new DateTime from this time + timedelta.
Args:
hours: A float value in hours (e.g. .5 = half an hour)
"""
return self.add_minute(hour * 60)
[docs] def sub_hour(self, hour):
"""Create a new DateTime from this time - timedelta.
Args:
hour: A float value in hours (e.g. .5 is half an hour and 2 is two hours).
"""
return self.add_hour(-hour)
[docs] def to_simple_string(self, separator="_"):
"""Return a simplified string."""
return self.strftime('%d_%b_%H_%M').replace("_", separator)
def __str__(self):
"""Return date time as a string."""
return self.strftime('%d %b %H:%M')
[docs] def to_json(self):
"""Get date time as a dictionary."""
return {'year': self.year,
'month': self.month,
'day': self.day,
'hour': self.hour,
'minute': self.minute}
[docs] def ToString(self):
"""Overwrite .NET ToString."""
return self.__str__()
def __repr__(self):
"""Return date time as a string."""
return self.__str__()