diff options
author | Dominik Picheta <dominikpicheta@googlemail.com> | 2015-08-08 20:56:14 +0100 |
---|---|---|
committer | Dominik Picheta <dominikpicheta@googlemail.com> | 2015-08-08 20:56:14 +0100 |
commit | 34ca9dd5861d5504bbbeb71469318c8c8caba6d7 (patch) | |
tree | b5407a18ced4924d66b71cd742103fa25c07da24 | |
parent | 4f8d982d5b0944f7f2bfc905c428ed81c3bd75bd (diff) | |
parent | f9d909bb947749666c0241f64bd8adef8c071a9b (diff) | |
download | Nim-34ca9dd5861d5504bbbeb71469318c8c8caba6d7.tar.gz |
Merge pull request #3114 from coffeepots/patch-1
Procs to decode Time to TimeInfo & TimeInterval
-rw-r--r-- | lib/pure/times.nim | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 78629af71..d9abbed1a 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1052,6 +1052,117 @@ proc parse*(value, layout: string): TimeInfo = info.weekday = getLocalTime(timeInfoToTime(info)).weekday return info +# Leap year calculations are adapted from: +# from http://www.codeproject.com/Articles/7358/Ultra-fast-Algorithms-for-Working-with-Leap-Years +# The dayOfTheWeek procs are adapated from: +# from http://stason.org/TULARC/society/calendars/2-5-What-day-of-the-week-was-2-August-1953.html + +# Note: for leap years, start date is assumed to be 1 AD. +# counts the number of leap years up to January 1st of a given year. +# Keep in mind that if specified year is a leap year, the leap day +# has not happened before January 1st of that year. +proc countLeapYears(yearSpan: int): int = + (((yearSpan - 1) / 4) - ((yearSpan - 1) / 100) + ((yearSpan - 1)/400)).int + +proc countDays(yearSpan: int): int = + (yearSpan - 1) * 365 + countLeapYears(yearSpan) + +proc countYears(daySpan: int): int = + # counts the number of years spanned by a given number of days. + ((daySpan - countLeapYears(daySpan div 365)) div 365) + +proc countYearsAndDays(daySpan: int): tuple[years: int, days: int] = + # counts the number of years spanned by a given number of days and the remainder as days. + let days = daySpan - countLeapYears(daySpan div 365) + result.years = days div 365 + result.days = days mod 365 + +const + secondsInMin = 60 + secondsInHour = 60*60 + secondsInDay = 60*60*24 + epochStartYear = 1970 + +proc getDayOfWeek*(day, month, year: int): WeekDay = + ## Returns the day of the week enum from day, month and year. + # Day & month start from one. + let + a = (14 - month) div 12 + y = year - a + m = month + (12*a) - 2 + d = (day + y + (y div 4) - (y div 100) + (y div 400) + (31*m) div 12) mod 7 + # The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. so we must correct + # for the WeekDay type. + if d == 0: return dSun + result = (d-1).WeekDay + +proc getDayOfWeekJulian*(day, month, year: int): WeekDay = + ## Returns the day of the week enum from day, month and year, according to the Julian calender. + # Day & month start from one. + let + a = (14 - month) div 12 + y = year - a + m = month + (12*a) - 2 + d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7 + result = d.WeekDay + +proc timeToTimeInfo*(t: Time): TimeInfo = + ## Converts a Time to TimeInfo. + let + daysSinceEpoch = t.int div secondsInDay + (yearsSinceEpoch, daysRemaining) = countYearsAndDays(daysSinceEpoch) + daySeconds = t.int mod secondsInDay + + y = yearsSinceEpoch + epochStartYear + + var + mon = mJan + days = daysRemaining + daysInMonth = getDaysInMonth(mon, y) + + # calculate month and day remainder + while days > daysInMonth and mon <= mDec: + days -= daysInMonth + mon.inc + daysInMonth = getDaysInMonth(mon, y) + + let + yd = daysRemaining + m = mon # month is zero indexed enum + md = days + # NB: month is zero indexed but dayOfWeek expects 1 indexed. + wd = getDayOfWeek(days, mon.int + 1, y).Weekday + h = daySeconds div secondsInHour + 1 + mi = (daySeconds mod secondsInHour) div secondsInMin + s = daySeconds mod secondsInMin + result = TimeInfo(year: y, yearday: yd, month: m, monthday: md, weekday: wd, hour: h, minute: mi, second: s) + +proc timetoTimeInterval*(t: Time): TimeInterval = + ## Converts a Time to a TimeInterval. + var + daysSinceEpoch = t.int div secondsInDay + (yearsSinceEpoch, daysRemaining) = countYearsAndDays(daysSinceEpoch) + daySeconds = t.int mod secondsInDay + + result.years = yearsSinceEpoch + epochStartYear + + var + mon = mJan + days = daysRemaining + daysInMonth = getDaysInMonth(mon, result.years) + + # calculate month and day remainder + while days > daysInMonth and mon <= mDec: + days -= daysInMonth + mon.inc + daysInMonth = getDaysInMonth(mon, result.years) + + result.months = mon.int + 1 # month is 1 indexed int + result.days = days + result.hours = daySeconds div secondsInHour + 1 + result.minutes = (daySeconds mod secondsInHour) div secondsInMin + result.seconds = daySeconds mod secondsInMin + # Milliseconds not available from Time when isMainModule: # $ date --date='@2147483647' @@ -1137,3 +1248,18 @@ when isMainModule: assert "15:04:00" in $s.parse(f) when not defined(testing): echo "Kitchen: " & $s.parse(f) + var ti = timeToTimeInfo(getTime()) + echo "Todays date after decoding: ", ti + var tint = timeToTimeInterval(getTime()) + echo "Todays date after decoding to interval: ", tint + # checking dayOfWeek matches known days + assert getDayOfWeek(21, 9, 1900) == dFri + assert getDayOfWeek(1, 1, 1970) == dThu + assert getDayOfWeek(21, 9, 1970) == dMon + assert getDayOfWeek(1, 1, 2000) == dSat + assert getDayOfWeek(1, 1, 2021) == dFri + # Julian tests + assert getDayOfWeekJulian(21, 9, 1900) == dFri + assert getDayOfWeekJulian(21, 9, 1970) == dMon + assert getDayOfWeekJulian(1, 1, 2000) == dSat + assert getDayOfWeekJulian(1, 1, 2021) == dFri |