home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / dongrovs.zip / mytimezone.cmd < prev    next >
OS/2 REXX Batch file  |  1996-10-16  |  31KB  |  736 lines

  1. /* ********************************************************************* */
  2. /*   By: Jetnick Enterprise                                              */
  3. /*       Don E. Groves, Jr.                                              */
  4. /*   Contact Information:                                                */
  5. /*     E-mail: jetnick@erols.com                                         */
  6. /*        CIS: 71310,3702                                                */
  7. /* Date: 18 Sep 1996                                                     */
  8. /* ********************************************************************* */
  9. /* public Classes and Routines                                           */
  10. /*  .MyTimeZone    Factory for producing TimeStamps                      */
  11. /*  ParseDateStr( inStrDate )                                            */
  12. /*         Convert a Message Date String into a TimeStamp.               */
  13. /* ********************************************************************* */
  14. /*  This file REQUIRES DateTime.CMD to function.                         */
  15. /* ********************************************************************* */
  16. /* This file is primary intented use is as a ::REQUIRES type file.       */
  17. /* ********************************************************************* */
  18. /*  General Documentation for other Programmer type Users                */
  19. /*                                                                       */
  20. /*  Class TimeStamp a Subclass of DateTime                               */
  21. /*                                                                       */
  22. /*   This is a results object from MyTimeZone class/object methods.      */
  23. /*     {New version cannot be produce except from copies of the object   */
  24. /*      or by the MyTimeZone methods.}                                   */
  25. /*                                                                       */
  26. /*       Inherates all methods from DateTime.                            */
  27. /*                                                                       */
  28. /*   Overrides:                                                          */
  29. /*     String        Parameters: (none)                                  */
  30. /*       Returns: A message(DATE:) fully formatted including UTC offset. */
  31. /*                                                                       */
  32. /*     compareBy return UTC useful in generic sorts and compares.        */
  33. /*                                                                       */
  34. /*   Adds the following:                                                 */
  35. /*     UtcOffSet Attribute     {Offset in Seconds from UTC}              */
  36. /*                                                                       */
  37. /*     UTC      Parameters: (none)                                       */
  38. /*       Returns:  NTS value adjusted to UTC                             */
  39. /*                                                                       */
  40. /*     ToUTC    Parameters: (none)                                       */
  41. /*       Returns: a new DateTime object equal to this objects            */
  42. /*               DateTime expressed in  UTC timezone                     */
  43. /*                                                                       */
  44. /*     Tz1      Parameters: (none)                                       */
  45. /*       Returns: String UTC offset. Useful in Message(Date:) fields.    */
  46. /*                                                                       */
  47. /*     MakeLocalTimeStamp Parameters: (none)                             */
  48. /*       Returns: A copy of this object adjusted to the Local time Zone. */
  49. /*                                                                       */
  50. /*     MakeTimeStamp      Parameters: (none)                             */
  51. /*       Returns: a copy of this object.                                 */
  52. /*                                                                       */
  53. /*     MakeUtcTimeStamp   Parameters: (none)                             */
  54. /*       Returns: A copy of this object adjusted to UTC time Zone.       */
  55. /*                                                                       */
  56. /* ********************************************************************* */
  57. /*                                                                       */
  58. /*   Class MyTimeZone  a public Factory for creating TimeStamp objects   */
  59. /*      Has all methods of the TimeStamp with one difference             */
  60. /*     All CLASS members are also Instances methods.                     */
  61. /*                                                                       */
  62. /*   Only methods with a difference parameter sequences are:             */
  63. /*    TZ          Returns current TZ Object.                             */
  64. /*                TZ(string)  sets MyTimeZone~TZ to new value.           */
  65. /*                                                                       */
  66. /*    NEW         Returns a handle to a .MyTimeZone object.              */
  67. /*                                                                       */
  68. /*    ParseDateStr(Message Date String)                                  */
  69. /*       Returns a TimeZone object built from the String                 */
  70. /*       or .NIL on invalid Message Date String.                         */
  71. /*                                                                       */
  72. /*    UtcToLocal( DT )                                                   */
  73. /*      Parameter is a required DateTime object respenting a UTC time    */
  74. /*      Returns: a Local TimeStamp object built from the object.         */
  75. /*                                                                       */
  76. /*    MakeLocalTimeStamp                                                 */
  77. /*      If parameter is supplied then same as UtcToLocal                 */
  78. /*      else return a TimeZone object built from the current Clock.      */
  79. /*                                                                       */
  80. /*    All other methods have the following first parameter format.       */
  81. /*      Paramter(optional) is DateTime for which to build the            */
  82. /*      new object from else the current Clock is used.                  */
  83. /*                                                                       */
  84. /*    TimeStamp         Returns a TimeStamp Object.                      */
  85. /*                                                                       */
  86. /*    MakeTimeStamp     Returns a TimeStamp Object.                      */
  87. /*                                                                       */
  88. /* ********************************************************************* */
  89. /*                                                                       */
  90. /*  class TZ       This is the TimeZone information object returned by   */
  91. /*                 MyTimeZone method TZ.                                 */
  92. /*                                                                       */
  93. /*       Following methods are documented as available:                  */
  94. /*                                                                       */
  95. /*    String       returns objects TZ string respentation                */
  96. /*                                                                       */
  97. /*    MakeString   {same as above}                                       */
  98. /*                                                                       */
  99. /*    Report       Returns multi-record textual string detailing         */
  100. /*                 interpetation of TZ input string.                     */
  101. /*                 {each record marked by LF ('0A'x) characters}         */
  102. /*                                                                       */
  103. /* ********************************************************************* */
  104. /*  All other classes defined in this file arenot visable outside of it. */
  105. /* ********************************************************************* */
  106. /*                                                                       */
  107. /* ********************************************************************* */
  108. /* ********************************************************************* */
  109. parse source . invhow myName
  110. RtCode = 0
  111. SELECT
  112.  WHEN invhow == 'FUNCTION'
  113.  THEN RtCode = .MyTimeZone
  114.  WHEN invhow == 'COMMAND'
  115.  THEN DO
  116.     IF Arg(1)~length \= 0
  117.     THEN DO
  118.        elsp = .Elasp_time~NEW
  119.        .OUTPUT~LINEOUT('Start report time:'~' '(elsp))
  120.        .OUTPUT~LINEOUT('')
  121.     END
  122.     .OUTPUT~LINEOUT('Current MessDate is:'~' '(.MyTimeZone))
  123.     .OUTPUT~LineOut(.MyTimeZone~TZ~Report)
  124.     IF Arg(1)~length \= 0
  125.     THEN DO
  126.        .OUTPUT~LINEOUT('')
  127.        .OUTPUT~LINEOUT('Total report time:'~' '(elsp))
  128.     END
  129.     RtCode = 1
  130.  END
  131.  WHEN invhow == 'SUBROUTINE'
  132.   THEN nop  /* happens when '::requires MyTimeZone' or 'call MyTimeZone' is used */
  133.  OTHERWISE
  134.    nop /* I've no idea, but then maybe everything will work out OK anyway. */
  135. END
  136. Return RtCode
  137.  
  138. ::requires DateTime
  139.  
  140.  /* This is a Factory for creating 'TimeStamp' objects. */
  141.  /* All public 'Method's take an optional DateTime object. */
  142.  /* Except */
  143.  /*   NEW          {no parameters} */
  144.  /*   ParseDateStr A String repesenting the Date, Time and TZ to use. */
  145.  /*   UtcToLocal   A DateTime in UTC to make a local TimeStamp from. */
  146. ::class MyTimeZone subclass Clock public
  147.  
  148. ::method TZ       CLASS     /* Returns current TZ Object */
  149.   use arg zt
  150.   IF ARG() = 0              /* If no arguments to get-in and get-out fast */
  151.   THEN forward to (.TimeZoneS)
  152. return .TimeZoneS~TZ(zt~MakeString)   /* LOCK MyTimeZone while update taking place. */
  153. ::method TZ                /* Returns copy of current TZ Object */
  154.   forward to (Self~Class)
  155.  
  156. ::method ArgHelper private class
  157. return Arg(2,'A')   /* Strip off one Argument and return the remaining. */
  158.  
  159. ::method UNKNOWN CLASS      /* How some of the magic is handled */
  160.   use arg cMsg, ARGS
  161.     /* Give a reasonable Error message for Assignment attempts. */
  162.   IF cMsg~RIGHT(1) == '='
  163.   THEN RAISE syntax 97.1 array(Self~OBJECTNAME,cMsg)
  164.     /* Create a 'TimeStamp' with the possible argument. */
  165.   forward continue message 'TimeStamp' ARGUMENTS (ARGS)
  166.   hrult = RESULT   /* save the resulting object */
  167.   forward continue message 'ArgHelper' ARGUMENTS (ARGS)
  168.     /* Now let the first resulting object handle the message */
  169.     /* and any remaining arguments. */
  170.   forward to (hrult) message (cMsg) ARGUMENTS ( RESULT )
  171.  
  172. ::method MakeDateTime CLASS  /* Create a DateTime object from an optional */
  173.   if arg(1,'O')            /* DateTime object. If no arg then use current */
  174.   THEN forward class (super) /* DateTime. {Sounds silly, but the combo happens.} */
  175. forward to (Arg(1)) ARGUMENTS ( .ARRAY~NEW )
  176.           /* Also allows this object to handle copies of itself, while */
  177.           /* maintaining the same syntax for all methods, */
  178.  
  179. ::method TimeStamp CLASS
  180.   use arg dt      /* Create a TimeStamp from an optional DateTime object */
  181.   if arg(1,'O')
  182.   then dt = .Clock    /* if no arg use current time */
  183. forward to (.TimeZoneS) Array (dt~MakeDateTime, .False )
  184. ::method TimeStamp           /* Make instances look the same */
  185.   forward to (Self~class)
  186. ::method MakeTimeStamp CLASS
  187.   forward message 'TimeStamp'
  188. ::method MakeTimeStamp       /* Make instances look the same */
  189.   forward to (Self~class)
  190.  
  191. ::method UtcToLocal Class  /* converts a UtC DateTime object to Local Time */
  192.   use arg DT
  193.   if arg(1,'O')
  194.   THEN RAISE syntax 93.901 array(1)
  195. forward to (.TimeZoneS) message 'TimeStamp' Array (dt~MakeDateTime, .True )
  196. ::method UtcToLocal
  197.   forward to (Self~class)
  198.  
  199. ::method MakeLocalTimeStamp CLASS
  200.   if arg(1,'O')
  201.   THEN forward message 'TimeStamp'
  202.   forward message 'UtcToLocal'
  203. ::method MakeLocalTimeStamp  /* Make instances look the same */
  204.   forward to (Self~class)
  205.  
  206. /* ****************************************** */
  207. /* Parses a Message Date String Data          */
  208. /*  Returns                                   */
  209. /*   a TimeStamp object built from the string */
  210. /*   or .NIL on error                         */
  211. /* ****************************************** */
  212. ::method ParseDateStr class
  213.   use arg inStrDate
  214.   IF ARG(1,'E')
  215.   THEN DO
  216.      inStrDate = inStrDate~MakeString
  217.      tz = ''
  218.      parse value inStrDate with dowt day month year tm tz TRASH
  219.      if dowt~datatype('N')
  220.      THEN DO
  221.         tz = ''
  222.         parse value inStrDate with day month year tm tz TRASH
  223.         if tm~length = 8
  224.         THEN dowt = 'm,'   /* flag that it is ok to proceed */
  225.         ELSE DO
  226.            if tm~length = 5
  227.            THEN DO
  228.               parse value tm with hh ':' mm
  229.               if hh~datatype('W')
  230.               THEN if hh < 24
  231.               then if mm~datatype('W')
  232.               then if mm < 60
  233.               THEN DO
  234.                  tm = tm~''(':00')
  235.                  dowt = 'm,'  /* flag that it is ok to proceed */
  236.               end
  237.            END
  238.         END
  239.      END
  240.      if dowt~pos(',') \= 0
  241.      then do
  242.         IF year < 100
  243.         THEN year= 1900 + year
  244.         IF year < 1970
  245.         THEN year= 100 + year
  246.         /* Trap possible invalid Date and/or Time information. */
  247.         SIGNAL ON SYNTAX name pDateTrap
  248.         strDate = DATE('N',day month year,'N')
  249.         IF DATE('B',strDate,'N') >= Self~NTS_Base
  250.         THEN DO
  251.            strTime = TIME('N',tm,'N')
  252.            forward to (.TimeZoneS) Array (strDate, strTime, tz)
  253.         END
  254.      end
  255.   end
  256. pDateTrap:
  257. return .nil   /* invalid Date Time Stamp String */
  258. ::method ParseDateStr        /* Make instances look the same */
  259.   forward to (Self~class)
  260.  
  261.   /* This is the results object from MyTimeZone class/object methods */
  262.   /* Yes it's a DateTime type object. */
  263. ::class TimeStamp Subclass DateTime
  264. ::method UtcOffSet Attribute     /* Seconds from UTC */
  265. ::method init
  266.   use arg DT, UtcOffSet
  267.   forward continue class (Super) Array ( dt )
  268.   Self~UtcOffSet = UtcOffSet
  269. return Self
  270. ::method UTC       /* Returns NTS normalized to UTC. */
  271. return Self~Nts - Self~UtcOffSet
  272. ::method ToUTC     /* Returns a new DateTime object adjusted to UTC. */
  273.   forward to (.DateTime) message 'NEW' Array ( Self~UTC )
  274. ::method compareBy     /* override to use Normalized value */
  275.   forward message 'UTC'
  276. ::method Tz1       /* String UTC offset */
  277.   tz1 = 'UTC'
  278.   wrk = Self~UtcOffSet
  279.   IF wrk~ABS \= 0
  280.   THEN DO
  281.      IF wrk < 0
  282.      then tz1 = '-'
  283.      else tz1 = '+'
  284.      wrk = wrk~Abs
  285.      tz1 = tz1~''('00'~''(wrk % 3600)~Right(2))
  286.      wrk = wrk // 3600
  287.      tz1 = tz1~''('00'~''(wrk % 60)~Right(2))
  288.   END
  289. forward to (tz1) message 'MakeString'
  290. ::method String          /* A message DATE: fully formatted */
  291. return (Self~String:Super)~' '(Self~tz1)
  292. ::method MessDate        /* A message DATE: fully formatted */
  293.   forward message 'String'
  294. ::method MakeLocalTimeStamp
  295.   forward to (.MyTimeZone) message 'UtcToLocal' array (Self~ToUtc)
  296. ::method MakeTimeStamp
  297.   forward to (.TimeStamp) message 'NEW' array (Self~Nts,Self~UtcOffSet)
  298. ::method MakeUtcTimeStamp
  299.   forward to (.TimeStamp) message 'NEW' array (Self~Utc,0)
  300.  
  301.   /* Holds the Start/END information of DayLight Savings */
  302.   /* used by .TZ class to pass infomation internally. */
  303. ::class TzDli_Data
  304. ::method init
  305.   expose Month Week Day rTime
  306.   use arg Month, Week, Day, rTime
  307. return Self
  308. ::method Month
  309.   expose Month Week Day rTime
  310. return Month
  311. ::method Week
  312.   expose Month Week Day rTime
  313. return Week
  314. ::method Day
  315.   expose Month Week Day rTime
  316. return Day
  317. ::method rTime
  318.   expose Month Week Day rTime
  319. return rTime
  320.  
  321. ::class TzDli subclass TzDli_Data
  322. ::method String
  323. return (Self~Month)~''(',')~''(Self~Week)~''(',')~''(Self~Day)~''(',')~''(Self~rTime)
  324. ::method MakeString
  325.   forward message 'String'
  326. ::method UNKNOWN  /* let the string respentation handle anything else */
  327.   forward to (Self~String) message (arg(1)) ARGUMENTS ( arg(2) )
  328. ::method MakeTzDli
  329. return .TzDli~New(Self~Month, Self~Week, Self~Day, Self~rTime)
  330. ::method Find
  331.   use arg DT
  332.   wrk = (DT~Date('S')~Left(4))~''('00'~''(Self~Month)~Right(2))~''('01')
  333.   wrk = .DateTime~NEW(DATE('N',wrk,'S'),TIME('N',Self~rTime,'S'))
  334.   SecPerDay  = wrk~SecPerDay  /* a handy constant */
  335.   SELECT
  336.    WHEN Self~WEEK > 0   /* from Start of Month */
  337.    THEN DO
  338.       IF Self~WEEK > 1
  339.       THEN  wrk = wrk + ((Self~WEEK - 1) * (SecPerDay * 7))
  340.       IF wrk~Dow \= Self~DAY
  341.       THEN wrk = wrk + ((7 - wrk~Dow) * SecPerDay)
  342.    END
  343.    WHEN Self~WEEK < 0  /* from End of Month */
  344.    THEN DO
  345.       wrk = wrk + (27 * SecPerDay) /* get near the end of the month */
  346.       mth = wrk~Date('M')
  347.       Do until wrk~Date('M') \== mth
  348.         wrk = wrk + SecPerDay
  349.       END
  350.       wrk = wrk - SecPerDay
  351.       /* wrk now equals last day of month */
  352.       IF Self~WEEK~ABS > 1
  353.       THEN wrk = wrk - ((Self~WEEK~ABS - 1) * (SecPerDay * 7))
  354.       IF wrk~Dow \= Self~DAY
  355.       THEN wrk = wrk - ((wrk~Dow - Self~Day) * SecPerDay)
  356.    END
  357.    OTHERWISE DO /* Fixed Day of Month */
  358.       wrk = wrk + (( Self~Day - 1 ) * SecPerDay)
  359.    END
  360.   END
  361. return wrk
  362. ::METHOD TzDli CLASS
  363.   use arg mh,wk,day,zt
  364.   DlS = .nil
  365.   IF mh > 0 & mh < 13 & zt >= 0 & zt < (24 * 3600) & wk~ABS >= 0 & wk~ABS < 5
  366.   THEN IF ( wk = 0 & day > 0 ) | (wk \= 0 & wk~ABS < 5 & day >= 0 & day < 7)
  367.   THEN DlS = .TzDli~NEW( mh, wk, day, zt )
  368. return DlS
  369.  
  370.  /* The Decoded TZ information get stored in one of theses */
  371. ::class TZ_Data
  372. ::method init
  373.   expose DlS STD difDlS UtcOffSet DlSStart DlSEnd
  374.   use arg DlS, STD, UtcOffSet, difDlS, DlSStart, DlSEnd
  375. return Self
  376. ::method DlS        /* This Local TimeZone String daylight Savings */
  377.   expose DlS STD difDlS UtcOffSet DlSStart DlSEnd
  378. forward to (DlS) message 'MakeString'
  379. ::method STD        /* This Local TimeZone String Standard Time */
  380.   expose DlS STD difDlS UtcOffSet DlSStart DlSEnd
  381. forward to (StD) message 'MakeString'
  382. ::method difDlS     /* Difference between daylight Savings and Standard. */
  383.   expose DlS STD difDlS UtcOffSet DlSStart DlSEnd
  384. forward to (difDlS) message 'MakeString'
  385. ::method UtcOffSet  /* Seconds from UTC standard */
  386.   expose DlS STD difDlS UtcOffSet DlSStart DlSEnd
  387. forward to (UtcOffSet) message 'MakeString'
  388. ::method DlSStart   /* Start datedata of Daylight Savings information */
  389.   expose DlS STD difDlS UtcOffSet DlSStart DlSEnd
  390. return DlSStart
  391. ::method DlSEnd     /* End datedata of Daylight Savings information */
  392.   expose DlS STD difDlS UtcOffSet DlSStart DlSEnd
  393. return DlSEnd
  394.  
  395. ::class TZ subclass TZ_Data
  396. ::method TimeStamp               /* returns a TimeStamp built from DT */
  397.   use arg DT, who
  398.   UtcOffSet = Self~UtcOffSet
  399.   difDlS    = Self~difDlS
  400.   IF difDlS \= 0
  401.   THEN DO     /* daylight Savings is observed. */
  402.      wrk    = Self~DlSStart~Find(DT)~Nts
  403.      EndWrk = Self~DlSEnd~Find(DT)~Nts
  404.      IF who
  405.      THEN DO  /* Is it a UTC refence object? */
  406.         wrk    = wrk    - UtcOffSet
  407.         Endwrk = Endwrk - UtcOffSet
  408.      END
  409.      Nts    = DT~Nts
  410.      IF ((wrk < Nts) & (endWrk > Nts))    /* DayLight Savings Time */
  411.      THEN UtcOffSet = UtcOffSet + difDlS
  412.   END
  413.   IF who     /* Is it a UTC refence object? */
  414.   THEN DT = DT + UtcOffSet    /* Then adjust to local time zone. */
  415. forward to (.TimeStamp) message 'New' Array(DT, UtcOffSet)
  416. ::method MakeTZ
  417. return .TZ~NEW(Self~DlS, Self~STD, Self~UtcOffSet, Self~difDlS, Self~DlSStart~MakeTzDli, Self~DlSEnd~MakeTzDli)
  418. ::method String          /* return current TZ string respentation */
  419.   secoff = Self~UtcOffSet
  420.   IF secOff \= 0
  421.   THEN DO
  422.      IF (secoff~Abs // 3600) \= 0
  423.      then hrs = TIME('N',secoff~ABS,'S')~Left(5)
  424.      else hrs = secoff~Abs % 3600
  425.      hrs = hrs~strip('L','0')
  426.      IF secoff > 0
  427.      then hrs = '-'~''(hrs)
  428.      ELSE hrs = '+'~''(hrs)
  429.   END
  430.   ELSE hrs = '0'
  431. return Self~STD~''(hrs)~''(Self~DlS)~''(',')~''(Self~DlSStart)~''(',')~''(Self~DlSEnd)~''(',')~''(Self~difDlS)
  432. ::method MakeString
  433.   forward message 'String'
  434. ::method TZ               /* Returns current TZ string respentation */
  435.   forward message 'String'
  436. ::method UNKNOWN  /* let the string respentation handle anything else */
  437.   forward to (Self~String) message (Arg(1)) ARGUMENTS (ARG(2))
  438. ::method Report
  439.   forward to (.Formatter~New) Array (Self)
  440. /* ******************************************************************** */
  441. /* TZ = ,array~of(EST+5EDT,4,1,0,3600,10,-1,0,7200,3600)                */
  442. /*                                                                      */
  443. /* TZ[1]  = 'EST+5EDT'  {EST +5 EDT}                                    */
  444. /* TZ[2]  = 4      month                                                */
  445. /* TZ[3]  = 1      starting week or 0                                   */
  446. /* TZ[4]  = 0      dayofweek(0-6) or start day if 3 was zero            */
  447. /* TZ[5]  = 3600   starting time in seconds local                       */
  448. /* TZ[6]  = 10     starting month                                       */
  449. /* TZ[7]  = -1     starting week of winter time (see 3 for details)     */
  450. /* TZ[8]  = 0      dayofweek(0-6) or start day if 7 was zero            */
  451. /* TZ[9]  = 7200   winter starting time in seconds local                */
  452. /* TZ[10] = 3600   Offset differences                                   */
  453. /*                                                                      */
  454. /* TZ[1]                                                                */
  455. /*  Std  3 Characters (must begin with a letter {space is legal after}) */
  456. /* ---                                                                  */
  457. /* of   sign {optional}     West is Plus East is minus                  */
  458. /* utc   x numbers and or ':'   {H}H {: MM {: SS}}                      */
  459. /* ---                                                                  */
  460. /*  dls  3 Characters (must begin with a letter {space is legal after}) */
  461. /*                                                                      */
  462. /* default:                                                             */
  463. /*    SET TZ=EST+5EDT,4,1,0,3600,10,-1,0,7200,3600                      */
  464. /* ******************************************************************** */
  465. ::METHOD TZ  CLASS
  466.   Use arg EST5EDT
  467.   IF ARG(1,'O')
  468.   THEN EST5EDT = ''
  469.   ELSE EST5EDT = EST5EDT~MakeString
  470.   argsGood = .False
  471.   UtcOffSet = 'ERR'
  472.   DLSSTD = ''
  473.   parse value EST5EDT with tz1','DLSSTD
  474.   if tz1~length > 0
  475.   THEN DO
  476.      StD = TZ1~LEFT(3)
  477.      tz1 = TZ1~SubStr(4)
  478.      lnum = ''
  479.      Do while '0123456789+-:'~pos(tz1~LEFT(1)) \= 0
  480.        lnum = lnum~''(tz1~LEFT(1))
  481.        tz1 = tz1~Substr(2)
  482.      END
  483.      IF lnum~Length \= 0
  484.      THEN DO
  485.         DlS = tz1~LEFT(3)
  486.         tsign = 1
  487.         IF tz1~left(1) = '-'
  488.         THEN DO
  489.            tsign = -1
  490.            lnum = lnum~SubStr(2)
  491.         END
  492.         IF lnum~POS(':') \= 0
  493.         THEN DO
  494.            parse value lnum with hr':'mm':'.
  495.            IF hr~''(mm)~DataType('N')
  496.            THEN UtcOffSet = 3600 * hr + 60 * mm
  497.         END
  498.         ELSE IF Lnum~DataType('N')
  499.         THEN UtcOffSet = 3600 * lnum
  500.         IF UtcOffSet~DataType('N')
  501.         THEN IF UtcOffSet > ( 12 * 3600 )
  502.         THEN UtcOffSet = 'ERR'
  503.         ELSE DO
  504.            UtcOffSet = UtcOffSet * tSign
  505.            UtcOffSet = -1 * UtcOffSet
  506.            IF DLSSTD~LENGTH > 0
  507.            THEN DO
  508.               /* decode the long string */
  509.               tz = .ARRAY~NEW
  510.               DO i = 1 to 9 WHILE DLSSTD~LENGTH > 0
  511.                 parse value DLSSTD with ln','DLSSTD
  512.                 IF ln~DataType('N')
  513.                 THEN tz[i] = ln
  514.                 else LEAVE
  515.               END
  516.               IF TZ~Items = 9 & DLSSTD~LENGTH = 0
  517.               THEN DO
  518.                  DlSStart =  .TzDli~TzDli( TZ[1], TZ[2], TZ[3], TZ[4] )
  519.                  IF DlSStart \= .nil
  520.                  THEN DO
  521.                     DlSEnd = .TzDli~TzDli( TZ[5], TZ[6], TZ[7], TZ[8] )
  522.                     IF DlSEnd \= .nil & TZ[9] >= 0 & TZ[9] < (24 * 3600)
  523.                     THEN DO
  524.                        difDlS   = TZ[9]
  525.                        argsGood = .TRUE
  526.                     END
  527.                  END
  528.               END
  529.            END
  530.         END
  531.      END
  532.   END
  533.   IF \ UtcOffSet~DataType('N')
  534.   THEN DO
  535.      DlS = 'EDT'
  536.      STD = 'EST'
  537.      UtcOffSet = (-5 * 3600)
  538.   END
  539.   IF \ argsGood
  540.   THEN DO
  541.      difDlS   = 3600
  542.      DlSStart = .TzDli~NEW( 4, 1,0,3600)
  543.      DlSEnd   = .TzDli~NEW(10,-1,0,7200)
  544.   END
  545. return .TZ~NEW(DlS, STD, UtcOffSet, difDlS, DlSStart, DlSEnd)
  546.  
  547. ::class Formatter_Buf           /* Helper object to format the report */
  548. ::method init                   /* for a TZ object method Report. */
  549.   expose buf
  550.   buf = ''
  551. return Self
  552. ::method CharOut private
  553.   expose buf
  554.   use arg cln
  555.   buf = buf~''(cln~MakeString)
  556. return Self
  557. ::method EofSignal private    /* return the buffer as a string */
  558.   expose buf
  559. forward to (buf) message 'MakeString' Arguments ( .Array~New )
  560. ::class Formatter subclass Formatter_Buf
  561. ::method Fmtnum private
  562.   use arg num
  563.   pre = '   '
  564.   forward message 'CharOut' Array ((pre)~''(num)~right(3))
  565. ::method FmtMonth  private
  566.   use arg month
  567.   Self~Fmtnum(month)~CharOut(' ')
  568. forward message 'CharOut' Array (DATE('M','96/'~''('00'~''(Month)~Right(2))~''('/01'),'O'))
  569. ::method FmtDay  private
  570.   use arg Day
  571.   Self~Fmtnum(day)~CharOut(' ')
  572. forward message 'CharOut' Array (DATE('W',.DateTime~NTS_Base + 3 + Day,'B'))
  573. ::method RepTime private
  574.   use arg secoff
  575.   hrs = ' '
  576.   IF Arg(2,'O')
  577.   THEN DO
  578.      Select
  579.       when secoff > 0 then hrs = '+'
  580.       when secoff < 0 then hrs = '-'
  581.       OTHERWISE NOP
  582.     END
  583.   END
  584.   Self~CharOut(hrs)~CharOut(TIME('N',secoff~ABS,'S'))
  585. forward message 'CharOut' Array ((' (')~''(secoff)~''(')'))
  586. ::method Tittle private
  587.   use arg what
  588. forward message 'CharOut' Array (('0A'x)~''('  ')~''(what))
  589. ::method RptMain private
  590.   use arg what
  591. forward message 'Tittle' Array ('  '~''(what)~''(' ')~Left(31,'.')~''(' = '))
  592. ::method SubHeader private
  593.   use arg what
  594. forward message 'RptMain' Array ('  '~''(what))
  595. ::method Subline private
  596.   use arg what
  597. forward message 'SubHeader' Array ('  '~''(what))
  598. ::method ReptHelper private
  599.   use arg dls, who
  600.   Self~SubHeader((who)~' '('information'))~CharOut(dls)
  601.   Self~Subline('Month')~FmtMonth(dls~Month)
  602.   IF dls~week \= 0
  603.   THEN DO
  604.      Self~SubLine('Week of month')~FmtNum(dls~Week)
  605.      Self~CharOut(' from the ')
  606.      IF dls~week > 0
  607.      THEN Self~CharOut('beginning')
  608.      ELSE Self~CharOut('end')
  609.      Self~CharOut(' of month')
  610.      Self~SubLine('Day of week')~FmtDay(dls~Day)
  611.   END
  612.   ELSE Self~SubLine('Fixed day of month')~FmtNum(dls~Day)
  613.   Self~SubLine('Time of day')~RepTime(dls~rTime,1)
  614.   Self~SubLine((who)~''('s this year'))
  615. forward message 'CharOut' Array (dls~Find(.clock))
  616. ::method Report        /* format the Report and return. */
  617.   use arg TZ           /* a TZ object */
  618.   Self~Tittle('TZ information report')
  619.   Self~RptMain('TZ repesentation')~CharOut(TZ)
  620.   Self~RptMain('Standard string')~CharOut(TZ~STD)
  621.   Self~RptMain('Offset from UTC (seconds)')~RepTime(TZ~UtcOffSet)
  622.   IF TZ~difDlS \= 0
  623.   THEN DO
  624.      Self~RptMain('Daylight savings string')~CharOut(TZ~DlS)
  625.      Self~RptMain('Daylight savings is')~CharOut('Observed')
  626.      Self~reptHelper(TZ~DLSStart, 'Start')
  627.      Self~reptHelper(TZ~DLSEnd  , 'End'  )
  628.      Self~SubHeader('Difference is')~RepTime(TZ~difDlS)
  629.   END
  630.   ELSE Self~RptMain('Daylight savings is')~CharOut('NOT observed')
  631.   Self~Tittle('End of report '~Left(76,'.'))
  632. forward message 'EofSignal'
  633.  
  634.  /* Static local TimeZone Table holder. */
  635.  /* Lets the constant information be built only once per session. */
  636.  /* Used by: .MyTimeZone class */
  637.  /*  To confussing to make these Expose(s) part of the class proper. */
  638. ::class TimeZoneS
  639. ::method init class
  640.   expose Gmtime. TzCur TzDef
  641.   rpErr = .nil
  642.   Gmtime.    = rpErr
  643.   Gmtime.ERR = rpErr
  644.   Gmtime.GMT = 0
  645.   Gmtime.UTC = 0
  646.   Gmtime.UT  = 0
  647.   Gmtime.ADT = (-03 * 3600 )
  648.   Gmtime.AST = (-04 * 3600 )
  649.   Gmtime.EDT = (-04 * 3600 )
  650.   Gmtime.EST = (-05 * 3600 )
  651.   Gmtime.CDT = (-05 * 3600 )
  652.   Gmtime.CST = (-06 * 3600 )
  653.   Gmtime.MDT = (-06 * 3600 )
  654.   Gmtime.MST = (-07 * 3600 )
  655.   Gmtime.PDT = (-07 * 3600 )
  656.   Gmtime.PST = (-08 * 3600 )
  657.   TzCur      = .TZ~TZ(VALUE('TZ',,'OS2ENVIRONMENT'))
  658.   TzDef      = .nil
  659. return Self
  660.  
  661. ::Method TZ  class    /* always returns a copy */
  662.   expose Gmtime. TzCur TzDef
  663.   IF ARG(1,'E')
  664.   THEN TzCur = .TZ~TZ(ARG(1))
  665. forward to (TzCur) message 'MakeTZ' Arguments ( .Array~new)
  666.  
  667. ::Method TimeStamp class     /* for internal MyTimeZone.CMD useage only */
  668.   expose Gmtime. TzCur TzDef
  669. forward to (TzCur)
  670.  
  671. ::Method ParseDateStr class     /* for internal MyTimeZone.CMD useage only */
  672.   expose Gmtime. TzCur TzDef
  673.   use arg strDate, strTime, zt
  674.   UtcOffSet = Self~TimeZ(zt)
  675.   if UtcOffSet \= .nil   /* was TZ valid */
  676.   THEN DO
  677.      DT = .DateTime~NEW(strDate,strTime)
  678.      IF \ UtcOffSet~dataType('N')
  679.      THEN DO             /* If no timeZone inf use default */
  680.         IF TzDef = .nil      /* Delay initalization of TzDef until needed */
  681.         THEN TzDef = .TZ~TZ
  682.         forward to (TzDef) message 'TimeStamp' Array ( DT, .False )
  683.      END
  684.      forward to (.TimeStamp) message 'New' Array (DT, UtcOffSet)
  685.   END
  686. return .nil
  687.  
  688. ::Method timeZ private  class /* returns offset field converted to seconds */
  689.   expose Gmtime. TzCur TzDef
  690.   use arg zt
  691.   /* check timezone stamp */
  692.   zt=zt~strip  /* strip any leading or trailing white space */
  693.   Select
  694.    WHEN zt~length = 0 THEN zt = '*'  /* Flag that ZT was blank */
  695.    WHEN zt~datatype('W') = 1
  696.    then DO
  697.       if zt \= 0
  698.       then DO
  699.          ztt  = zt~substr(2,2)
  700.          zttm = zt~substr(4,2)
  701.          ztts = 1
  702.          SELECT
  703.           WHEN zt~substr(1,1) == '-' then ztts = -1
  704.           WHEN zt~substr(1,1) == '+' then NOP
  705.           OTHERWISE do
  706.              ztt = zt~substr(1,2)
  707.              zttm = zt~substr(3,2)
  708.           END
  709.          END
  710.          if zttm~strip~length = 0
  711.          then zttm = 0
  712.          zt = ztts * (( ztt * 3600 ) + ( zttm * 60 ))
  713.          if zt~abs > (12 * 3600) | zt~DataType('W') = 0
  714.          then zt = GmTime.ERR
  715.       end
  716.    END
  717.    OTHERWISE zt = GmTime.[zt~Translate]
  718.   END
  719. return zt
  720.  
  721. /* ****************************************************************** */
  722. /* Parses a Message Date String Data                                  */
  723. /*  Returns                                                           */
  724. /*   a TimeStamp object built from the string                         */
  725. /*   or .NIL on error                                                 */
  726. /* {Hey, I first though I wanted a function type interface for this.} */
  727. /* ****************************************************************** */
  728. ::ROUTINE ParseDateStr public
  729.   use arg inStrDate
  730. return .MyTimeZone~ParseDateStr(inStrDate)
  731.  
  732. /* ************************************ */
  733. /* EOF MyTimeStame.CMD                  */
  734. /* ************************************ */
  735.  
  736.