2 # -*- coding: koi8-r -*-
5 # opDate - date/time manipulation routines
6 # Some ideas came from Turbo Professional/Object Professional (t/o)pDate.PAS
10 from __future__ import print_function
13 from calendar import *
14 from opstring import *
19 MinDate = 0x00000000 # = 01/01/1600
20 MaxDate = 0x000D6025 # = 12/31/3999
21 Date1900 = 0x0001AC05 # = 01/01/1900
22 Date1980 = 0x00021E28 # = 01/01/1980
23 Date2000 = 0x00023AB1 # = 01/01/2000
28 MinTime = 0 # = 00:00:00 am
29 MaxTime = 86399 # = 23:59:59 pm
32 SecondsInDay = 86400 # number of seconds in a day
33 SecondsInHour = 3600 # number of seconds in an hour
34 SecondsInMinute = 60 # number of seconds in a minute
35 HoursInDay = 24 # number of hours in a day
36 MinutesInHour = 60 # number of minutes in an hour
38 First2Months = 59 # 1600 was a leap year
39 FirstDayOfWeek = 5 # 01/01/1600 was a Saturday
43 class opdate_error(Exception):
48 ### Date manipulation routines
52 if ( (Year % 4 == 0) and (Year % 4000 != 0) and ((Year % 100 != 0) or (Year % 400 == 0)) ):
61 if Year < Threshold2000:
66 def DaysInMonth(Month, Year):
67 """ Return the number of days in the specified month of a given year """
68 if Month in [1, 3, 5, 7, 8, 10, 12]:
71 elif Month in [4, 6, 9, 11]:
75 return 28+IsLeapYear(_setYear(Year))
78 raise opdate_error("bad month `%s'" % str(Month))
81 def ValidDate(Day, Month, Year):
82 """ Verify that day, month, year is a valid date """
85 if (Day < 1) or (Year < MinYear) or (Year > MaxYear):
87 elif (Month >= 1) and (Month <= 12):
88 return Day <= DaysInMonth(Month, Year)
93 def DMYtoDate(Day, Month, Year):
94 """ Convert from day, month, year to a julian date """
97 if not ValidDate(Day, Month, Year):
100 if (Year == MinYear) and (Month < 3):
111 Year = Year - MinYear
113 return (((Year // 100)*146097) // 4) + (((Year % 100)*1461) // 4) + (((153*Month)+2) // 5)+Day+First2Months
116 def DateToDMY(Julian):
117 """ Convert from a julian date to day, month, year """
118 if Julian == BadDate:
121 if Julian <= First2Months:
130 I = (4*(Julian-First2Months))-1
131 J = (4*((I % 146097) // 4))+3
132 Year = (100*(I // 146097))+(J // 1461)
133 I = (5*(((J % 1461)+4) // 4))-3
135 Day = ((I % 153)+5) // 5
141 Year = Year + MinYear
143 return Day, Month, Year
146 def IncDate(Julian, Days, Months, Years):
147 """ Add (or subtract) the number of months, days, and years to a date.
148 Months and years are added before days. No overflow/underflow checks are made
150 Day, Month, Year = DateToDMY(Julian)
158 Year = Year + Months // 12
159 Month = Month + Months % 12
167 Julian = DMYtoDate(Day, Month, Year)
168 if Julian != BadDate:
169 Julian = Julian + Days + Day28Delta
174 def IncDateTrunc(Julian, Months, Years):
175 """ Add (or subtract) the specified number of months and years to a date """
176 Day, Month, Year = DateToDMY(Julian)
184 Year = Year + Months // 12
185 Month = Month + Months % 12
193 Julian = DMYtoDate(Day, Month, Year)
194 if Julian != BadDate:
195 MaxDay = DaysInMonth(Month, Year)
196 if Day+Day28Delta > MaxDay:
197 Julian = Julian + MaxDay-Day
199 Julian = Julian + Day28Delta
204 def DateDiff(Date1, Date2):
205 """ Return the difference in days,months,years between two valid julian dates """
206 #we want Date2 > Date1
212 #convert dates to day,month,year
213 Day1, Month1, Year1 = DateToDMY(Date1)
214 Day2, Month2, Year2 = DateToDMY(Date2)
222 Day2 = Day2 + DaysInMonth(Month2, Year2)
223 Days = abs(Day2-Day1)
225 #now months and years
229 Months = Month2-Month1
232 return Days, Months, Years
235 def DayOfWeek(Julian):
236 """ Return the day of the week for the date. Returns DayType(7) if Julian == BadDate. """
237 if Julian == BadDate:
238 raise opdate_error("bad date `%s'" % str(Julian))
240 return (Julian+FirstDayOfWeek) % 7
243 def DayOfWeekDMY(Day, Month, Year):
244 """ Return the day of the week for the day, month, year """
245 return DayOfWeek( DMYtoDate(Day, Month, Year) )
248 #def MonthStringToMonth(MSt):
249 # """ Convert the month name in MSt to a month (1..12) or -1 on error """
250 # lmn = strptime.LongMonthNames[strptime.LANGUAGE]
251 # smn = strptime.ShortMonthNames[strptime.LANGUAGE]
252 # lmna = LongMonthNamesA
254 # I = FindStr(MSt, lmn)+1 or FindStr(MSt, smn)+1 or \
255 # FindStrUC(MSt, lmn)+1 or FindStrUC(MSt, smn)+1 or \
256 # FindStr(MSt, lmna)+1 or FindStrUC(MSt, lmna)+1
262 """ Returns today's date as a julian """
263 Year, Month, Day = localtime(time())[0:3]
264 return DMYtoDate(Day, Month, Year)
267 ### Time manipulation routines
271 """ Convert a Time variable to Hours, Minutes, Seconds """
276 Hours = T // SecondsInHour
277 T = T - Hours*SecondsInHour
278 Minutes = T // SecondsInMinute
279 T = T - Minutes*SecondsInMinute
282 return Hours, Minutes, Seconds
285 def HMStoTime(Hours, Minutes, Seconds):
286 """ Convert Hours, Minutes, Seconds to a Time variable """
287 Hours = Hours % HoursInDay
288 T = Hours*SecondsInHour + Minutes*SecondsInMinute + Seconds
290 return T % SecondsInDay
293 def ValidTime(Hours, Minutes, Seconds):
294 """ Return true if Hours:Minutes:Seconds is a valid time """
295 return (0 <= Hours < 24) and (0 <= Minutes < 60) and (0 <= Seconds < 60)
299 """ Returns current time in seconds since midnight """
300 Hours, Minutes, Seconds = localtime(time())[3:6]
301 return HMStoTime(Hours, Minutes, Seconds)
304 def TimeDiff(Time1, Time2):
305 """ Return the difference in hours,minutes,seconds between two times """
311 Hours, Minutes, Seconds = TimeToHMS(T)
312 return Hours, Minutes, Seconds
315 def IncTime(T, Hours, Minutes, Seconds):
316 """ Add the specified hours,minutes,seconds to T and return the result """
317 T = T + HMStoTime(Hours, Minutes, Seconds)
318 return T % SecondsInDay
321 def DecTime(T, Hours, Minutes, Seconds):
322 """ Subtract the specified hours,minutes,seconds from T and return the result """
323 Hours = Hours % HoursInDay
324 T = T - HMStoTime(Hours, Minutes, Seconds)
326 return T+SecondsInDay
331 def RoundToNearestHour(T, Truncate = False):
332 """ Round T to the nearest hour, or Truncate minutes and seconds from T """
333 Hours, Minutes, Seconds = TimeToHMS(T)
337 if Minutes >= (MinutesInHour // 2):
341 return HMStoTime(Hours, Minutes, Seconds)
344 def RoundToNearestMinute(T, Truncate = False):
345 """ Round T to the nearest minute, or Truncate seconds from T """
346 Hours, Minutes, Seconds = TimeToHMS(T)
349 if Seconds >= (SecondsInMinute // 2):
350 Minutes = Minutes + 1
353 return HMStoTime(Hours, Minutes, Seconds)
356 def DateTimeDiff(DT1, DT2):
357 """ Return the difference in days,seconds between two points in time """
358 # swap if DT1 later than DT2
359 if (DT1[0] > DT2[0]) or ((DT1[0] == DT2[0]) and (DT1[1] > DT2[1])):
364 # the difference in days is easy
367 # difference in seconds
369 # subtract one day, add 24 hours
371 DT2[1] = DT2[1] + SecondsInDay
377 def IncDateTime(DT1, Days, Secs):
378 """ Increment (or decrement) DT1 by the specified number of days and seconds
379 and put the result in DT2 """
383 DT2[0] = DT2[0] + Days
390 DT2[0] = DT2[0] - Secs // SecondsInDay
391 Secs = Secs % SecondsInDay
394 # subtract a day from DT2[0] and add a day's worth of seconds to DT2[1]
396 DT2[1] = DT2[1] + SecondsInDay
398 # now subtract the seconds
399 DT2[1] = DT2[1] - Secs
402 # increment the seconds
403 DT2[1] = DT2[1] + Secs
405 # adjust date if necessary
406 DT2[0] = DT2[0] + DT2[1] // SecondsInDay
408 # force time to 0..SecondsInDay-1 range
409 DT2[1] = DT2[1] % SecondsInDay
418 UTC_0Date = DMYtoDate(1, 1, 1970)
421 def DateTimeToGMT(Date, Time = False):
422 Date = Date - UTC_0Date
423 return Date*SecondsInDay + Time
426 def GMTtoDateTime(GMT):
427 q, r = divmod(GMT, SecondsInDay)
428 return q + UTC_0Date, r
435 LongMonthNamesA = ['Января', 'Февраля', 'Марта', 'Апреля', 'Мая', 'Июня',
436 'Июля', 'Августа', 'Сентября', 'Октября', 'Ноября', 'Декабря']
444 print("Is 1984 leap year?", IsLeapYear(1984))
445 print("Is 1990 leap year?", IsLeapYear(1990))
447 print("Days in month 8 year 1996:", DaysInMonth(8, 1996))
449 print("Is date 8/12/1996 valid?", ValidDate(8, 12, 1996))
450 print("Is date 40/11/1996 valid?", ValidDate(40, 11, 1996))
451 print("Is date 8/14/1996 valid?", ValidDate(8, 14, 1996))
453 print("Date->DMY for 138219:", DateToDMY(138219))
455 diff = DateDiff(DMYtoDate(12, 10, 1996), DMYtoDate(12, 10, 1997))
456 print("Date 12/10/1996 and date 12/10/1997 diff: %d years, %d months, %d days" % (diff[2], diff[1], diff[0]))
458 diff = DateDiff(DMYtoDate(12, 10, 1996), DMYtoDate(12, 11, 1997))
459 print("Date 12/10/1996 and date 12/11/1997 diff: %d years, %d months, %d days" % (diff[2], diff[1], diff[0]))
461 diff = DateDiff(DMYtoDate(31, 1, 1996), DMYtoDate(1, 3, 1996))
462 print("Date 31/01/1996 and date 01/03/1996 diff: %d years, %d months, %d days" % (diff[2], diff[1], diff[0]))
465 #print("November is %dth month" % MonthStringToMonth("November"))
467 print("Today is", Today())
468 print("Now is", CurrentTime())
470 print("My birthday 21 Dec 1967 is (must be Thursday):", day_name[DayOfWeekDMY(21, 12, 67)])
472 gmt = DateTimeToGMT(DMYtoDate(21, 12, 1967), HMStoTime(23, 45, 0))
473 # DOS version of gmtime has error processing dates before 1/1/1970 :(
474 print("21 Dec 1967, 23:45:00 --", gmtime(gmt))
475 D, T = GMTtoDateTime(gmt)
476 print("(gmt) --", DateToDMY(D), TimeToHMS(T))
478 if __name__ == "__main__":