Unix Date and Time Conversions┌───────────────────────────────────────┐ │ Unix Time and Date Conversions │ │ Author: Phil Pilgrim │ │(c) Copyright 2012 Bueno Systems, Inc. │ │ See end of file for terms of use. │ └───────────────────────────────────────┘ This object converts between Unix time and other date/time formats. Revision History 2012.03.27: v1.0 Initial release. Contact Information Phil Pilgrim: propeller@phipi.com IntroductionThis object provides methods that convert back and forth between Unix time and year.month.day hour:minute:second values. Unix time is a signed, 32-bit integer representing the number of seconds elapsed since 01 Jan 1970 at 00:00:00 UTC, ignoring leap seconds. The object also provides date and time from Unix time in ASCII string format.Instance VariablesSOURCE CODE... byte dt_str[16] 'Buffer for date strings. byte tm_str[12] 'Buffer for time strings. Public Spin Methodsunix_time(yr, mo, da, hr, mn, sec, timezone)Convert date and time to Unix time.Parameters:
yr: Year number: must be entire number, e.g. 1984, not 84.
mo: Month number: 1 == Jan, ..., 12 == Dec.
da: Day number: 1 .. 31.
hr: Hour: 0 .. 23.
mn: Minute: 0 .. 59.
sec: Second: 0 .. 59.
timezone: Timezone for time and date given: -12 .. 12, e.g. 0 == UTC, -5 == EST, -7 == PDT, etc.
Return: A signed 32-bit integer representing Unix time in whole seconds.
Example: utime := udt.unix_time(2000, 1, 1, 12, 0, 0, -6)
Return Unix time for 1 Jan 2000 at 12 noon CST and assigne to the long variable utime.
SOURCE CODE... PUB unix_time(yr, mo, da, hr, mn, sec, timezone) | a if (mo < 3) yr-- mo += 12 a := yr / 100 return ((36525 * yr) / 100 + 306001 * (mo + 1) / 10000 + da - a + a ~> 2 - 719591) * 86400 + (hr - timezone) * 3600 + mn * 60 + sec date_time24_str(unixtime, timezone)Given Unix time and a local timezone, produce a string in the format: "Wdy dd Mmm yyyy hh:mm:ss"Parameters:
unixtime: Unix time in whole seconds.
timezone: Timezone for date returned: -12 .. 12, e.g. 0 == UTC, -5 == EST, -7 == PDT, etc.
Return: Address of the resulting date/time string.
NOTE: The contents of this string are transient and must be either copied or output before another
date string method in this object is called.
Example: sio.str(udt.date_time24_str(1_000_000_000, -4))
Output a string representing the date given by 1_000_000_000 (in Unix time), corrected for EDT
(in this case the string "Sat 08 Sep 2001 01:46:40").
SOURCE CODE... PUB date_time24_str(unixtime, timezone) date_str(unixtime, timezone) time24_str(unixtime, timezone) dt_str[15] := " " return @dt_str date_time12_str(unixtime, timezone)Given Unix time and a local timezone, produce a string in the format: "Wdy dd Mmm yyyy hh:mm:ss xm"Parameters:
unixtime: Unix time in whole seconds.
timezone: Timezone for date returned: -12 .. 12, e.g. 0 == UTC, -5 == EST, -7 == PDT, etc.
Return: Address of the resulting date/time string.
NOTE: The contents of this string are transient and must be either copied or output before another
date string method in this object is called.
Example: sio.str(udt.date_time24_str(1_000_000_000, -4))
Output a string representing the date given by 1_000_000_000 (in Unix time), corrected for EDT
(in this case the string "Sat 08 Sep 2001 01:46:40 am").
SOURCE CODE... PUB date_time12_str(unixtime, timezone) date_str(unixtime, timezone) time12_str(unixtime, timezone) dt_str[15] := " " return @dt_str date_str(unixtime, timezone)Given Unix time and a local timezone, produce a string in the format: "day dd Mmm yyyy"Parameters:
unixtime: Unix time in whole seconds.
timezone: Timezone for date returned: -12 .. 12, e.g. 0 == UTC, -5 == EST, -7 == PDT, etc.
Return: Address of the resulting date string.
NOTE: The contents of this string are transient and must be either copied or output before another
date string method in this object is called.
Example: sio.str(udt.date_str(1_000_000_000, -4))
Output a string representing the date given by 1_000_000_000 (in Unix time), corrected for EDT
(in this case the string "Sat 08 Sep 2001").
SOURCE CODE... PUB date_str(unixtime, timezone) | yyyymmdd yyyymmdd := date(unixtime, timezone) bytefill(@dt_str, " ", 15) dt_str[15]~ dec(@dt_str[4], yyyymmdd.byte[0], 2) dec(@dt_str[11], yyyymmdd.word[1], 4) bytemove(@dt_str, weekday_str(weekday(unixtime, timezone)), 3) bytemove(@dt_str[7], month_str(yyyymmdd.byte[1]), 3) return @dt_str time24_str(unixtime, timezone)Given Unix time and a local timezone, produce a zero-terminated ASCII string in the format: "hh:mm:ss" (24-hour format).Parameters:
unixtime: Unix time in whole seconds.
timezone: Timezone for time returned: -12 .. 12, e.g. 0 == UTC, -5 == EST, -7 == PDT, etc.
Return: Address of the resulting time string.
NOTE: The contents of this string are transient and must be either copied or output before another
time string method in this object is called.
Example: sio.str(udt.time24_str(1_000_000_000, 0))
Output a string representing the time given by 1_000_000_000 (in Unix time), UTC
(in this case the string "01:46:40").
SOURCE CODE... PUB time24_str(unixtime, timezone) | hhmmss bytemove(@tm_str, string("xx:xx:xx"), 9) hhmmss := time(unixtime, timezone) dec(@tm_str, hhmmss.byte[2], 2) dec(@tm_str[3], hhmmss.byte[1], 2) dec(@tm_str[6], hhmmss.byte[0], 2) return @tm_str time12_str(unixtime, timezone)Given Unix time and a local timezone, return a zero-terminated ASCII string in the format: "hh:mm:ss am" or "hh:mm:ss pm" (12-hour am/pm format).Parameters:
unixtime: Unix time in whole seconds.
timezone: Timezone for time returned: -12 .. 12, e.g. 0 == UTC, -5 == EST, -7 == PDT, etc.
Return: Address of the resulting time string.
NOTE: The contents of this string are transient and must be either copied or output before another
time string method in this object is called.
Example: sio.str(udt.time12_str(1_000_000_000, 0))
Output a string representing the time given by 1_000_000_000 (in Unix time), UTC
(in this case the string "01:46:40 am").
SOURCE CODE... PUB time12_str(unixtime, timezone) | hhmmss, hr bytemove(@tm_str, string("xx:xx:xx am"), 12) hhmmss := time(unixtime, timezone) if ((hr := hhmmss.byte[2]) > 12) tm_str[9] := "p" hr -= 12 if (hr == 0) hr := 12 dec(@tm_str, hr, 2) dec(@tm_str[3], hhmmss.byte[1], 2) dec(@tm_str[6], hhmmss.byte[0], 2) return @tm_str date(unixtime, timezone)Compute a calendar date from Unix time and a local timezone.Parameters:
unixtime: Unix time in whole seconds.
timezone: Timezone for date returned: -12 .. 12, e.g. 0 == UTC, -5 == EST, -7 == PDT, etc.
Return: A packed long containing the year in the upper word, the month in byte 1, and the day in byte 0.
Example: yyyymmdd := udt.date(1_234_567_890, 0)
Return the date (UTC) for Unix time == 1_234_567_890 (in this case 2009 << 16 | 2 << 8 | 13,
i.e. 13 Feb 2009), and assign it to the long variable yyyymmdd.
SOURCE CODE... PUB date(unixtime, timezone) : yyyymmdd | year, month, day, leap day := floor_div(unixtime + timezone * 3600, 86400) year := floor_div(day << 2 + 2, 1461) yyyymmdd.word[1] := year + 1970 leap := floor_mod(year, 4) == 2 day -= (year * 1461 + 1) ~> 2 if (day > 58 - leap) day += leap + 2 yyyymmdd.byte[1] := (day * 12 + 6) / 367 yyyymmdd.byte[0] := day + 1 - (yyyymmdd.byte[1]++ * 367 + 5) / 12 time(unixtime, timezone)Compute a time of day from Unix time and a local timezone.Parameters:
unixtime: Unix time in whole seconds.
timezone: Timezone for date returned: -12 .. 12, e.g. 0 == UTC, -5 == EST, -7 == PDT, etc.
Return: A packed long containing the hour in byte 2, minutes in byte 1, and seconds in byte 0.
Example: hhmmss := udt.time(1_234_567_890, -5)
Return the time (EST) for Unix time == 1_234_567_890 (in this case 16 << 16 | 31 << 8 | 30,
i.e. 16:31:30), and assign it to the long variable hhmmss.
SOURCE CODE... PUB time(unixtime, timezone) | hours, minutes, seconds seconds := floor_mod(unixtime + timezone * 3600, 86400) minutes := seconds / 60 seconds -= minutes * 60 hours := minutes / 60 minutes -= hours * 60 return hours << 16 + minutes << 8 + seconds weekday(unixtime, timezone)Compute the day of the week from the given Unix time and local timezone.Parameters:
unixtime: Unix time in whole seconds.
timezone: Timezone for date returned: -12 .. 12, e.g. 0 == UTC, -5 == EST, -7 == PDT, etc.
Return: Number (0 == Sun .. 6 == Sat) corresponding to the day of the week.
Example: wkday := udt.weekday(0, 0)
Find the day of the week corresponding to the beginning of the Unix epoch,
in this case 4 (Thursday) and assign it to the variable wkday.
SOURCE CODE... PUB weekday(unixtime, timezone) return floor_mod(floor_div(unixtime + timezone * 3600, 86400) + 4, 7) weekday_str(wkday)Given a weekday number, return the address of a zero-terminated ASCII string representing the day of the week.Parameters:
wkday: Weekday number (0 == Sun .. 6 == Sat).
Return: Address of a three-character ASCII string giving an abbreviation for the corresponding weekday.
Example: sio.str(udt.weekday_str(udt.weekday(0, 0)))
Output "Thu" to the serial port. (See example for weekday above.)
SOURCE CODE... PUB weekday_str(wkday) return @wkdays + (wkday // 7) << 2 month_str(month)Given a month number, return the address of an ASCII representing the day of the week.Parameters:
month: The number of the month (1 == Jan .. 12 == Dec).
Return: Address of a three-character ASCII string giving an abbreviation for the corresponding month.
Example: bytecopy(@my_month, udt.month_str(5), 4)
Copy the four bytes "May", 0 to the byte array my_month.
Next lines, if needed...
SOURCE CODE... PUB month_str(month) return @months + ((month - 1) // 12) << 2 Private Spin MethodsDecimal conversion and math floor routines.dec(addr, value, digits)Convert a value to ASCII decimal and copy the digits to an array whose address is given.Parameters:
addr: Address of the array to copy to.
value: Value of the number to convert.
digits: Number of least-significant digits to convert.
Return: none.
Example: dec(@str, 1234, 2)
Copies the digits "34" to the byte array str.
SOURCE CODE... PRI dec(addr, value, digits) | i repeat i from digits - 1 to 0 byte[addr][i] := value // 10 + "0" value /= 10 floor_div(numer, denom)Return the floor quotient of numer / denom. Floor quotient of -1/n == -1, -n/n == -1, -(n+1)/n == -2, etc.Parameters:
numer: Numerator.
denom: Denominator.
Return: Floor quotient of numer / denom.
SOURCE CODE... PRI floor_div(numer, denom) if (numer < 0) numer -= denom - 1 return numer / denom floor_mod(numer, denom)Return the floor modulus of numer // denom. Floor modulus of -1//n == n-1, -2//n == n-2, -n/n == 0, etc.Parameters:
numer: Numerator.
denom: Modulus.
Return: Floor modulus of numer // denom.
SOURCE CODE... PRI floor_mod(numer, denom) result := numer // denom if (result < 0) result += denom String ConstantsSOURCE CODE... wkdays byte "Sun",0,"Mon",0,"Tue",0,"Wed",0,"Thu",0,"Fri",0,"Sat" months byte "Jan",0,"Feb",0,"Mar",0,"Apr",0,"May",0,"Jun",0,"Jul",0,"Aug",0,"Sep",0,"Oct",0,"Nov",0,"Dec",0 License┌──────────────────────────────────────────────────────────────────────────────────────┐ │ TERMS OF USE: MIT License │ ├──────────────────────────────────────────────────────────────────────────────────────┤ │Permission is hereby granted, free of charge, to any person obtaining a copy of this │ │software and associated documentation files (the "Software"), to deal in the Software │ │without restriction, including without limitation the rights to use, copy, modify, │ │merge, publish, distribute, sublicense, and/or sell copies of the Software, and to │ │permit persons to whom the Software is furnished to do so, subject to the following │ │conditions: │ │ │ │The above copyright notice and this permission notice shall be included in all copies │ │or substantial portions of the Software. │ │ │ │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, │ │INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A │ │PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT │ │HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF │ │CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE │ │OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ └──────────────────────────────────────────────────────────────────────────────────────┘ |