370 likes | 693 Vues
12. 1. 11. 10. 2. 3. 9. 4. 8. 5. 7. 6. Date/Time Processing in User Language. Alex Kodat. Dates and Times. One of the most common types of data in applications Time stamps Last-modified times for HTTP Birth dates And other start dates Death dates And other end dates
E N D
12 1 11 10 2 3 9 4 8 5 7 6 Date/Time Processing in User Language Alex Kodat
Dates and Times • One of the most common types of data in applications • Time stamps • Last-modified times for HTTP • Birth dates • And other start dates • Death dates • And other end dates • Activity dates - prospective and retrospective • Recurring activity times
The Trouble With Dates And Times... • Irregular units • Seconds, minutes, hours • Thank you Dozenal Society (formerly the Duodecimal Society): http://www.polar.sunynassau.edu/~dozenal • For alternatives see http://www.decimaltime.hynes.net • Days, weeks, months, years • Damn the earth, sun and moon!
The Trouble With Dates And Times... • No standard representation • MM/DD/YY or YY/MM/DD or DD/MM/YY, etc. • Month DD YYYY or DD Month YYYY, etc. • YYYYMMDD • HH:MI:SS[AM|PM] or HH:MI:SS • With leading 0, leading blank or neither • YYNNN (Julian) • CYYMMDD (Thank you Y2K) • YYYYMMDDHHMISS, YYYYMMDDHHMISSXXX, etc. • Many more
The Trouble With Dates And Times • Calculations are complicated • How many seconds between 08:27:34 and 09:23:18? • How many days between January 17, 2004 and May 18, 2004? • What day of the week is April 2, 2001?
Dates and Times in Software • Much code devoted to dealing with time issues • Many bugs as a result • See Y2K "bug" • Much fluff in code to deal with date/time issues
Dates and Times in User Language • No native/primitive datetime datatype • Many implementations in other languages just a double precision fixed point number • So must be manipulated as Float, Fixed or String and stored as Float, Binary or String
Dates and Times as Strings • The classic approach in User Language • Human friendly (to some degree) • Standard date $functions all string-oriented
The Standard Date $functions... • $Date(format, fill-char) - Current date • format - 0, 1, or 2 • $date(1) = '2004-04-21' • $date(1, '') = '20040421' • $date(1, '/') = '2004/04/21' • $date = '04-04-21' • $date(2) = '104-02-21' • $date(3) = '***********'
The Standard Date $functions... • $DateChg(format, date, num-days) - Add/subtract days to/from date • format - Set of tokens - YYYY, YY, CYY, DD, DDD, MM, MON, MONTH • $dateChg('YYYY-MM-DD', '2004-03-15', 40) = '2004-04-24' • $dateChg('YYYYMMDD', '20040315', -100) = '20031206' • $dateChg('MON DD,YYYY', 'MAR 15, 2004', 77) = 'MAY 27,2004' • $dateChg('MAR 15, 2004', 'MON DD,YYYY', 77) = '***********' • $dateChg('MON DD,YYYY', 'FEB 29,2003' 77) = '***********'
The Standard Date $functions... • $DateDif(format1, date1, format2, date2, DefCent, CentSplit) - Get difference in days between two dates • format - Set of tokens - YYYY, YY, CYY, DD, DDD, MM, MON, MONTH • $dateDif('YYYY-MM-DD', '2004-03-15', - • 'YYYY-MM-DD', '2002-11-09') = 492 • $dateDif('YYYY-MM-DD', '2004-03-15', , '2002-11-09') = 492 • $dateDif('MONTH DD YYYY', 'APRIL 11 2002', - • 'YYYY-MM-DD', '2004-03-09') = -698 • $dateDif('MON DD YYYY', 'APRIL 11 2002', - • 'YYYY-MM-DD', '2004-03-09') = 99999999
The Standard Date $functions... • $DateCnv(in-format, out-format, date, DefCent, CentSplit) - Convert date format • format - Set of tokens - YYYY, YY, CYY, DD, DDD, MM, MON, MONTH • $dateCnv('MONTH DD YYYY', 'YYYY-MM-DD', • 'APRIL 11 2004') = '2004-04-11' • $dateCnv('MONTH DD YYYY', 'YYYY-MM-DD', • 'FEBRUARY 30 2003') = '**********'
The Standard Date $functions • $DateChk(in-format, out-format, date, DefCent, CentSplit) - Validate date format • format - Set of tokens - YYYY, YY, CYY, DD, DDD, MM, MON, MONTH • $DateJ(format, fill-char) - Get Julian format date • format - 0, 1, or 2 • $DAY(day-number) - gets day of week name • $DAY1(input-date, CentSplit) - Gets day of week for CYYDDD format date
The Problem With the Date $Functions • Several different $functions to remember • Each $function has different ideas about parameter order and format options • Limited formats • Lack of mixed case support • Error checking is difficult • No real support for time (hours, minutes, seconds)
Generic Problems With String Dates • No standard date format • Not clear in applications that a string is a date • Good idea to use naming conventions • Dates can have values that are invalid in a variety of ways • Bad characters • Bad format • Invalid dates - i.e. September 31, 2004
Recommendation - Try to Use Same Date Format for Everything • Have variable with standard date format, e.g. %dateFormat • Use Initial to set - so can't be Common (doh!) • Unless... see next page • Saves STBL, VTBL • Catches typing errors at compile-time • %days = $dateDif(%dateFormat, %date1, , %date2) • Best to use sort-friendly format like YYYYMMDD • So comparisons and sorts work easily
Dealing With Initial Clause Problem • Problem: Only first declaration of Common variable can contain Initial clause • Using the Sirius Macro Language - available to one and all in Sirius Mods 6.6: !ifndef var.dateFormat %dateFormat is string len 8 initial('YYYYMMDD') common !def var.dateFormat !else %dateFormat is string len 8 common !endif
The Sirius Approach to Date/Time Processing • $Functions provided to do numeric to string and string to numeric conversions • $Functions provided to get current date/time in numeric format • Numeric format is number of units since • January 1, 1900 00:00:00 • Sybase origin • Good new, bad news - Units can be milliseconds, seconds or days
The Sirius Date/Time $Functions • Available to all API customers • Janus Web, Fast Unload ULI, Janus SOAP, Janus Sockets, Sirius Functions • All begin with $SIR_DATE • Even though, strictly speaking, they're date/time $functions
Conversion $Functions • String to numeric • $sir_date2nm(date, format) - convert to milliseconds • $sir_date2ns(date, format) - convert to seconds • $sir_date2nd(date, format) - convert to days • Numeric to string • $sir_nm2date(date, format) - convert from milliseconds • $sir_ns2date(date, format) - convert from seconds • $sir_nd2date(date, format) - convert from days
Conversion $Functions - Word of Warning • Beware $sir_date2n and $sir_n2date • Units are bizarre 1/300ths of a second • Thanks Sybase • Preceded all the other date $functions
Conversion $Function Formats • Collection of tokens: • YYYY, YY, CYY, ZYY - Year • MONTH, MON, Month, Mon, MM, BM - Month • DDD, DD, BD, DAY - Day • HH, BH - Hours • MI - Minutes • SS - Seconds • X, XX, XXX - Fraction of second • WKDAY, Wkday, WKD, Wkd - Day of week • AM, PM - Duh • I, * - Placeholders
Conversion $Function Examples print $sir_date2nd('20021211', 'YYYYMMDD') print $sir_date2nm('20021211', 'YYYYMMDD') print $sir_date2ns('January 30, 2004', - 'MONTH DAY, YYYY') print $sir_date2ns('February 29, 2003, - 'MONTH DAY, YYYY') print $sir_nd2date(37599, - 'Wkday, MONTH DD YYYY') print $sir_ns2date(3284460333, - 'YY/MM/DD HH:MI:SS') print $sir_ns2date(3284460333, - 'HH:MI:SS') print $sir_ns2date(3284460333, 'WKD') ==> 37599 ==> 3248553600000 ==> 3284409600 ==> -9000000000000 ==> Wednesday, DECEMBER 11 2002 ==> 04/01/30 14:05:33 ==> 14:05:33 ===> FRI
Sirius Date $Function Examples **************************************************************** * Calculate number of days between start date and end date * **************************************************************** %days = $sir_date2nd(%endDate, 'YYYYMMDD') - - $sir_date2nd(%startDate, 'YYYYMMDD') **************************************************************** * Calculate date 60 days before expiry date * **************************************************************** %date = $sir_nd2date( $sir_date2nd(%expiryDate, 'YYYYMMDD') - 60, - 'YYYYMMDD') **************************************************************** * Calculate date and time 6 hours from now * **************************************************************** %time = $sir_ns2date( $sir_dateNs + 6 * 60 * 60, 'YYYYMMDDHHMISS')
User Language - Designed for Numeric Date/Time Values? • $sir_date2nm('December 31, 9999', 'Month DAY, YYYY') = 255611203200000 • But all User Language datatypes can handle up to 15 digits • So no danger of losing information when using Sirius date functions • Beware BINARY fields, though, can't hold seconds or milliseconds
Sirius Date $Function Advantages Over Standard Date $Functions • Easier to remember • Only three $function flavors: $sir_dateN?, $sir_date2n?, and $sir_n?2date • No complex parameter order issues • Handles date and time • Many more formats • Including mixed case • Easier to test for errors
Standard Date $Function Advantages Over Sirius Date $Functions • Sometimes can do in one $function what would take Sirius $functions two • Already in existing code • So programers know and love (?)
A Modest Proposal • Make all date/time variables in User Language code numeric • Recommended unit - milliseconds. • Extra resolution can't hurt, can it? • Life easier if units all the same • Restrict conversion $functions to interface points: screens, web pages and legacy stuff (including fields)
Life is Good When Date/Time Variables are Numeric Milliseconds **************************************************************** * Calculate number of days between start date and end date * **************************************************************** %days = (%endDate - %startDate) / (24 * 60 * 60 * 1000) **************************************************************** * Calculate date 60 days before expiry date * **************************************************************** %date = %expiryDate - 60 * 24 * 60 * 60 * 1000 **************************************************************** * Calculate date and time 6 hours from now * **************************************************************** %time = $sir_dateNs + 6 * 60 * 60 * 1000
Making Life Even Better • Define some standard "constants" • Variables with Initial clause (must use macro language trick for Common) • %second = 1000 • %minute = 60000 • %hour = 3600000 • %day = 86400000 • %week = 604800000 • %month? and %year?
Life even Better **************************************************************** * Calculate number of days between start date and end date * **************************************************************** %days = (%endDate - %startDate) / %day **************************************************************** * Calculate date 60 days before expiry date * **************************************************************** %date = %expiryDate - 60 * %day **************************************************************** * Calculate date and time 6 hours from now * **************************************************************** %time = $sir_dateNs + 6 * %hour
Advantages of Usually Holding Date/Time Values as Numeric • Common manipulations require no $functions • Difference = subtraction • Offset = addition • Comparisons work easily • Number of milliseconds provides a standard that should last forever
Still Some Issues, However • Easy to put garbage values into date variables • Since they're interchangeable with numbers • Not necessarily clear in code that a variable is a date/time • Code still has to check for errors • Shame on Sirius • Could probably be corrected
Classes/Objects to the Rescue? • Maybe • DateTime class could eliminate "garbage data" and code clarity issues • Eliminates need for special %variables • Can even have format defaults • Unfortunately, comparisons don't work "naturally"
Life with a DateTime Class **************************************************************** * Calculate number of days between start date and end date * **************************************************************** %days = %endDate:days - %startDate:days **************************************************************** * Calculate date 60 days before expiry date * **************************************************************** %date = %expiryDate:adddays(60) **************************************************************** * Calculate date and time 6 hours from now * **************************************************************** %time = currentTime:addHours(6)
Conclusions • Date/Time processing complex but important in User Language • Sirius date $functions useful "out of the wrapper" • Ignored issue - GMT vs. local time • Some other day • It's worth reconsidering general date/time strategy • Especially when going to web processing • Time stamps become important for Since-last processing and update validation
The time is gone, the song is over Thought I'd something more to say