time.ck 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842
  1. /*++
  2. Copyright (c) 2017 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. time.ck
  9. Abstract:
  10. This module implements support for time in Chalk.
  11. Author:
  12. Evan Green 10-Jan-2016
  13. Environment:
  14. Chalk
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. import _time;
  20. //
  21. // ---------------------------------------------------------------- Definitions
  22. //
  23. var daysPerMonth = [
  24. [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
  25. [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
  26. ];
  27. var monthDays = [
  28. [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
  29. [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
  30. ];
  31. var DAYS_IN_4_YEARS = 1461;
  32. var DAYS_IN_100_YEARS = 36524;
  33. var DAYS_IN_400_YEARS = 146097;
  34. var MAX_ORDINAL = 3652059;
  35. //
  36. // Define the ordinal for January 1, 1970.
  37. //
  38. var EPOCH_ORDINAL = 719163;
  39. //
  40. // ----------------------------------------------- Internal Function Prototypes
  41. //
  42. function
  43. _dateToOrdinal (
  44. year,
  45. month,
  46. day
  47. );
  48. function
  49. _ordinalToDate (
  50. ordinal
  51. );
  52. function
  53. _isoWeek1 (
  54. year
  55. );
  56. function
  57. _daysBeforeYear (
  58. year
  59. );
  60. function
  61. _daysBeforeMonth (
  62. year,
  63. month
  64. );
  65. //
  66. // -------------------------------------------------------------------- Globals
  67. //
  68. //
  69. // Instantiate the two main time zones.
  70. //
  71. var utc;
  72. var localTime;
  73. //
  74. // ------------------------------------------------------------------ Functions
  75. //
  76. function
  77. isLeapYear (
  78. year
  79. )
  80. /*++
  81. Routine Description:
  82. This routine returns whether or not the given year is a leap year.
  83. Arguments:
  84. year - Supplies the year.
  85. Return Value:
  86. true if the given year is a leap year.
  87. false if the given year is not a leap year.
  88. --*/
  89. {
  90. return ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
  91. }
  92. class TimeZoneNotImplemented is Exception {}
  93. class TimeOverflowError is Exception {}
  94. //
  95. // The TimeDelta class stores a relative time.
  96. //
  97. class TimeDelta {
  98. function
  99. __init (
  100. )
  101. /*++
  102. Routine Description:
  103. This routine initializes a time delta object with a delta of zero.
  104. Arguments:
  105. None.
  106. Return Value:
  107. Returns the initialized object.
  108. --*/
  109. {
  110. return this.__init(0, 0, 0);
  111. }
  112. function
  113. __init (
  114. days,
  115. seconds,
  116. nanoseconds
  117. )
  118. /*++
  119. Routine Description:
  120. This routine initializes a time delta object with the given values.
  121. Arguments:
  122. days - Supplies the number of days in the delta.
  123. seconds - Supplies the number of seconds in the delta. This will be
  124. normalized to a positive value between 0 and 86400 (exclusive).
  125. nanoseconds - Supplies the number of nanoseconds in the delta. This
  126. will be normalized to a positive value between 0 and 1000000000
  127. (exclusive).
  128. Return Value:
  129. Returns the initialized object.
  130. --*/
  131. {
  132. if ((!(days is Int)) || (!(seconds is Int)) ||
  133. (!(nanoseconds is Int))) {
  134. Core.raise(TypeError("Expected an integer"));
  135. }
  136. //
  137. // Normalize nanoseconds into seconds.
  138. //
  139. seconds += (nanoseconds / 1000000000);
  140. nanoseconds %= 1000000000;
  141. if (nanoseconds < 0) {
  142. nanoseconds += 1000000000;
  143. seconds -= 1;
  144. }
  145. //
  146. // Normalize seconds into days.
  147. //
  148. days += seconds / 86400;
  149. seconds %= 86400;
  150. if (seconds < 0) {
  151. seconds += 86400;
  152. days -= 1;
  153. }
  154. if ((days < -999999999) || (days > 999999999)) {
  155. Core.raise(TimeOverflowError());
  156. }
  157. super.__set("days", days);
  158. super.__set("seconds", seconds);
  159. super.__set("nanoseconds", nanoseconds);
  160. return this;
  161. }
  162. function
  163. totalSeconds (
  164. )
  165. /*++
  166. Routine Description:
  167. This routine returns the total number of seconds in the time delta
  168. object.
  169. Arguments:
  170. None.
  171. Return Value:
  172. Returns the number of seconds as an integer. Nanoseconds are ignored.
  173. --*/
  174. {
  175. return (this.days * 86400) + this.seconds;
  176. }
  177. function
  178. __set (
  179. key,
  180. value
  181. )
  182. /*++
  183. Routine Description:
  184. This routine prohibits setting of timedelta values, effectively making
  185. them immutable.
  186. Arguments:
  187. key - Supplies the key attempting to be set.
  188. value - Supplies the value attempting to be set.
  189. Return Value:
  190. Raises an error.
  191. --*/
  192. {
  193. Core.raise(ValueError("TimeDelta objects are immutable"));
  194. }
  195. function
  196. __add (
  197. right
  198. )
  199. /*++
  200. Routine Description:
  201. This routine adds two time delta's together.
  202. Arguments:
  203. right - Supplies the right side to add.
  204. Return Value:
  205. Returns a new time delta containing the sum.
  206. --*/
  207. {
  208. return TimeDelta(this.days + right.days,
  209. this.seconds + right.seconds,
  210. this.nanoseconds + right.nanoseconds);
  211. }
  212. function
  213. __sub (
  214. right
  215. )
  216. /*++
  217. Routine Description:
  218. This routine subtracts a time delta from this one.
  219. Arguments:
  220. right - Supplies the right side to add.
  221. Return Value:
  222. Returns the difference between the two time deltas.
  223. --*/
  224. {
  225. return TimeDelta(this.days - right.days,
  226. this.seconds - right.seconds,
  227. this.nanoseconds - right.nanoseconds);
  228. }
  229. function
  230. __eq (
  231. right
  232. )
  233. /*++
  234. Routine Description:
  235. This routine determines if two time deltas are equal.
  236. Arguments:
  237. right - Supplies the right side to compare against.
  238. Return Value:
  239. true if the values are equal.
  240. false if the values are not equal.
  241. --*/
  242. {
  243. if (!(right is TimeDelta)) {
  244. return false;
  245. }
  246. return (this.days == right.days) && (this.seconds == right.seconds) &&
  247. (this.nanoseconds == right.nanoseconds);
  248. }
  249. function
  250. __ne (
  251. right
  252. )
  253. /*++
  254. Routine Description:
  255. This routine determines if two time deltas are not equal.
  256. Arguments:
  257. right - Supplies the right side to compare against.
  258. Return Value:
  259. true if the values are not equal.
  260. false if the values are equal.
  261. --*/
  262. {
  263. return !this.__eq(right);
  264. }
  265. function
  266. __neg (
  267. )
  268. /*++
  269. Routine Description:
  270. This routine returns the negative of this time delta object, which
  271. simply negates the days.
  272. Arguments:
  273. None.
  274. Return Value:
  275. Returns a new time delta that is the negative of this time delta.
  276. --*/
  277. {
  278. return TimeDelta(-this.days, this.seconds, this.nanoseconds);
  279. }
  280. function
  281. abs (
  282. )
  283. /*++
  284. Routine Description:
  285. This routine returns the absolute value of the given time delta. It
  286. returns the same value if this object's days are >= 0, or -days if
  287. the days are less than zero.
  288. Arguments:
  289. None.
  290. Return Value:
  291. Returns a new time delta that is the absolute value.
  292. --*/
  293. {
  294. if (this.days >= 0) {
  295. return this;
  296. }
  297. return TimeDelta(-this.days, this.seconds, this.nanoseconds);
  298. }
  299. function
  300. __str (
  301. )
  302. /*++
  303. Routine Description:
  304. This routine returns a string representation of the time delta in the
  305. form "[D day[s], ][H]H:MM:SS[.NNNNNNNNN]".
  306. Arguments:
  307. None.
  308. Return Value:
  309. Returns a string representation of the time delta.
  310. --*/
  311. {
  312. var hours = this.seconds / 3600;
  313. var minutes = (this.seconds - (hours * 3600)) / 60;
  314. var result = "";
  315. var seconds = this.seconds % 60;
  316. if (this.days != 0) {
  317. if (this.days == 1) {
  318. result = "1 day, ";
  319. } else {
  320. result = "%d days, " % this.days;
  321. }
  322. }
  323. result += "%d:%02d:%02d" % [hours, minutes, seconds];
  324. if (this.nanoseconds != 0) {
  325. result += ".%09d" % this.nanoseconds;
  326. }
  327. return result;
  328. }
  329. function
  330. __repr (
  331. )
  332. /*++
  333. Routine Description:
  334. This routine returns a string representation of the time delta in the
  335. form "TimeDelta(D[, S[, N]])".
  336. Arguments:
  337. None.
  338. Return Value:
  339. Returns a string representation of the time delta.
  340. --*/
  341. {
  342. var result = "TimeDelta(%d" % this.days;
  343. if ((this.seconds != 0) || (this.nanoseconds != 0)) {
  344. result += ", %d" % this.seconds;
  345. if (this.nanoseconds != 0) {
  346. result += ", %d" % this.nanoseconds;
  347. }
  348. }
  349. return result + ")";
  350. }
  351. }
  352. //
  353. // The Time class stores a date and time, and is immutable.
  354. //
  355. class Time {
  356. static
  357. function
  358. fromTimestamp (
  359. timestamp,
  360. nanoseconds,
  361. zone
  362. )
  363. /*++
  364. Routine Description:
  365. This routine initializes a time object with a number of seconds since
  366. January 1, 1970 GMT and a time zone.
  367. Arguments:
  368. timestamp - Supplies the number of seconds since 1970.
  369. nanoseconds - Supplies the nanoseconds value to set.
  370. zone - Supplies the time zone.
  371. Return Value:
  372. Returns a new Time instance corresponding to the given timestamp.
  373. --*/
  374. {
  375. var utcTime = Time.fromUtcTimestamp(timestamp, nanoseconds);
  376. if (zone == null) {
  377. zone = localTime;
  378. }
  379. return zone.fromUtc(utcTime.replaceZone(zone));
  380. }
  381. static
  382. function
  383. fromUtcTimestamp (
  384. timestamp,
  385. nanoseconds
  386. )
  387. /*++
  388. Routine Description:
  389. This routine initializes a time object with a number of seconds since
  390. January 1, 1970 GMT and a time zone.
  391. Arguments:
  392. timestamp - Supplies the number of seconds since 1970.
  393. nanoseconds - Supplies the nanoseconds value to set.
  394. zone - Supplies the time zone.
  395. Return Value:
  396. Returns a new Time instance corresponding to the given timestamp.
  397. --*/
  398. {
  399. var result = Time();
  400. result._set("second", timestamp);
  401. result._set("nanosecond", nanoseconds);
  402. result._set("zone", utc);
  403. result._normalize();
  404. return result;
  405. }
  406. static
  407. function
  408. fromOrdinal (
  409. ordinal,
  410. zone
  411. )
  412. /*++
  413. Routine Description:
  414. This routine initializes a time object to be midnight on the given
  415. ordinal day.
  416. Arguments:
  417. ordinal - Supplies the ordinal day.
  418. zone - Supplies the time zone.
  419. Return Value:
  420. Returns a new Time instance corresponding to midnight on the given
  421. ordinal date.
  422. --*/
  423. {
  424. var ymd = _ordinalToDate(ordinal);
  425. return Time(ymd[0], ymd[1], ymd[2], 0, 0, 0, 0, zone);
  426. }
  427. static
  428. function
  429. now (
  430. )
  431. /*++
  432. Routine Description:
  433. This routine returns the current date and time in the platform's
  434. local time zone.
  435. Arguments:
  436. None.
  437. Return Value:
  438. Returns a new Time instance corresponding to the current time.
  439. --*/
  440. {
  441. var currentTime = (_time.clock_gettime)(_time.CLOCK_REALTIME);
  442. return Time.fromTimestamp(currentTime[0], currentTime[1], localTime);
  443. }
  444. static
  445. function
  446. nowUtc (
  447. )
  448. /*++
  449. Routine Description:
  450. This routine returns the current date and time in UTC time.
  451. Arguments:
  452. None.
  453. Return Value:
  454. Returns a new Time instance corresponding to the current time in
  455. Universal Coordinated Time.
  456. --*/
  457. {
  458. var currentTime = (_time.clock_gettime)(_time.CLOCK_REALTIME);
  459. return Time.fromUtcTimestamp(currentTime[0], currentTime[1]);
  460. }
  461. function
  462. __init (
  463. )
  464. /*++
  465. Routine Description:
  466. This routine initializes a time object with a value of midnight
  467. January 1, 1970, GMT.
  468. Arguments:
  469. None.
  470. Return Value:
  471. Returns the initialized object.
  472. --*/
  473. {
  474. return this.__init(1970, 1, 1, 0, 0, 0, 0, utc);
  475. }
  476. function
  477. __init (
  478. year,
  479. month,
  480. day,
  481. hour,
  482. minute,
  483. second,
  484. nanosecond,
  485. zone
  486. )
  487. /*++
  488. Routine Description:
  489. This routine initializes a time object with the given values.
  490. Arguments:
  491. year - Supplies the year. Valid years are between 1 and 9999, inclusive.
  492. month - Supplies the month. Valid months are between 1 and 12,
  493. inclusive.
  494. day - Supplies the day of the month. Valid days are between 1 and
  495. however many days the given year and month have, inclusive.
  496. hour - Supplies the hour. Valid values are between 0 and 23, inclusive.
  497. minute - Supplies the minute. Valid minutes are between 0 and 59,
  498. inclusive.
  499. second - Supplies the second. Valid seconds are between 0 and 60,
  500. inclusive. 60 is allowed to account for leap seconds.
  501. nanosecond - Supplies the nanosecond. Valid values are between 0 and
  502. 999999999, inclusive.
  503. zone - Supplies the time zone.
  504. Return Value:
  505. Returns the initialized object.
  506. --*/
  507. {
  508. var maxDay;
  509. if ((!(year is Int)) || (!(month is Int)) || (!(day is Int)) ||
  510. (!(hour is Int)) || (!(minute is Int)) || (!(second is Int)) ||
  511. (!(nanosecond is Int))) {
  512. Core.raise(TypeError("Expected an integer"));
  513. }
  514. if (zone == null) {
  515. Core.raise(TypeError("Expected a time zone"));
  516. }
  517. if ((year < 1) || (year > 9999)) {
  518. Core.raise(TimeOverflowError("Bad year %d" % year));
  519. }
  520. if ((month < 1) || (month > 12)) {
  521. Core.raise(TimeOverflowError("Bad month %d" % month));
  522. }
  523. maxDay = daysPerMonth[isLeapYear(year)][month - 1];
  524. if ((day < 1) || (day > maxDay)) {
  525. Core.raise(TimeOverflowError("Bad day %d (%02d/%04d has %d days)" %
  526. [day, month, year, maxDay]));
  527. }
  528. if ((hour < 0) || (hour > 23)) {
  529. Core.raise(TimeOverflowError("Bad hour %d" % hour));
  530. }
  531. if ((minute < 0) || (minute > 59)) {
  532. Core.raise(TimeOverflowError("Bad minute %d" % minute));
  533. }
  534. if ((second < 0) || (second > 60)) {
  535. Core.raise(TimeOverflowError("Bad second %d" % second));
  536. }
  537. if ((nanosecond < 0) || (nanosecond > 999999999)) {
  538. Core.raise(TimeOverflowError("Bad nanosecond %d" % nanosecond));
  539. }
  540. super.year = year;
  541. super.month = month;
  542. super.day = day;
  543. super.hour = hour;
  544. super.minute = minute;
  545. super.second = second;
  546. super.nanosecond = nanosecond;
  547. super.zone = zone;
  548. return this;
  549. }
  550. function
  551. replaceDate (
  552. year,
  553. month,
  554. day
  555. )
  556. /*++
  557. Routine Description:
  558. This routine returns a new date that is a copy of this one except with
  559. the given date.
  560. Arguments:
  561. year - Supplies the year the new date should have.
  562. month - Supplies the month the new date should have.
  563. day - Supplies the day the new day of the month the new date should
  564. have.
  565. Return Value:
  566. Returns a new Time instance with the given values, and the values of
  567. the current instance for time of day.
  568. --*/
  569. {
  570. return Time(year,
  571. month,
  572. day,
  573. this.hour,
  574. this.minute,
  575. this.second,
  576. this.nanosecond,
  577. this.zone);
  578. }
  579. function
  580. replaceTime (
  581. hour,
  582. minute,
  583. second,
  584. nanosecond
  585. )
  586. /*++
  587. Routine Description:
  588. This routine returns a new date that is a copy of this one except with
  589. the given time.
  590. Arguments:
  591. hour - Supplies the hour the new time should have (between 0 and 23).
  592. minute - Supplies the minute the new time should have.
  593. second - Supplies the second the new time should have.
  594. nanosecond - Supplies the nanosecond the new time should have.
  595. Return Value:
  596. Returns a new Time instance with the given time of day and the same
  597. date as the current instance.
  598. --*/
  599. {
  600. return Time(this.year,
  601. this.month,
  602. this.day,
  603. hour,
  604. minute,
  605. second,
  606. nanosecond,
  607. this.zone);
  608. }
  609. function
  610. midnight (
  611. )
  612. /*++
  613. Routine Description:
  614. This routine is shorthand for this.replacetime(0, 0, 0, 0).
  615. Arguments:
  616. None.
  617. Return Value:
  618. Returns a new time instance with the same date, at midnight.
  619. --*/
  620. {
  621. return Time(this.year, this.month, this.day, 0, 0, 0, 0, this.zone);
  622. }
  623. function
  624. replaceZone (
  625. zone
  626. )
  627. /*++
  628. Routine Description:
  629. This routine returns a new Time with a different time zone.
  630. Arguments:
  631. zone - Supplies the zone of the new date.
  632. Return Value:
  633. Returns a new Time instance with the same date and time as this
  634. instance, but with a new time zone.
  635. --*/
  636. {
  637. return Time(this.year,
  638. this.month,
  639. this.day,
  640. this.hour,
  641. this.minute,
  642. this.second,
  643. this.nanosecond,
  644. zone);
  645. }
  646. function
  647. weekday (
  648. )
  649. /*++
  650. Routine Description:
  651. This routine returns the weekday for the time value instance.
  652. Arguments:
  653. None.
  654. Return Value:
  655. Returns the weekday, where Monday is 0 and Sunday is 6.
  656. --*/
  657. {
  658. //
  659. // 1/1/1 was theoretically a Monday.
  660. //
  661. return (_dateToOrdinal(this.year, this.month, this.day) + 6) % 7;
  662. }
  663. function
  664. isoWeekday (
  665. )
  666. /*++
  667. Routine Description:
  668. This routine returns the ISO weekday for time instance.
  669. Arguments:
  670. None.
  671. Return Value:
  672. Returns the weekday, where Monday is 1 and Sunday is 7.
  673. --*/
  674. {
  675. //
  676. // 1/1/1 was theoretically a Monday.
  677. //
  678. return this.weekday() + 1;
  679. }
  680. function
  681. isoCalendar (
  682. )
  683. /*++
  684. Routine Description:
  685. This routine returns the ISO year, week, and weekday for this instance's
  686. time.
  687. Arguments:
  688. None.
  689. Return Value:
  690. Returns the [year, ISO week, weekday].
  691. --*/
  692. {
  693. var day;
  694. var today;
  695. var week;
  696. var year = this.year;
  697. var yearStart = _isoWeek1(year);
  698. today = _dateToOrdinal(year, this.month, this.day);
  699. week = (today - yearStart) / 7;
  700. day = (today - yearStart) - (week * 7);
  701. if (day < 0) {
  702. day += 7;
  703. week -= 1;
  704. }
  705. if (week < 0) {
  706. year -= 1;
  707. week = _isoWeek1(year);
  708. week = (today - yearStart) / 7;
  709. day = (today - yearStart) - (week * 7);
  710. } else if ((week >= 52) && (today >= _isoWeek1(year + 1))) {
  711. week = 0;
  712. year += 1;
  713. }
  714. return [year, week + 1, day + 1];
  715. }
  716. function
  717. ordinal (
  718. )
  719. /*++
  720. Routine Description:
  721. This routine returns the ordinal day of this date, where 1/1/0001 is
  722. ordinal day 1.
  723. Arguments:
  724. None.
  725. Return Value:
  726. Returns the ordinal day.
  727. --*/
  728. {
  729. return _dateToOrdinal(this.year, this.month, this.day);
  730. }
  731. function
  732. tzName (
  733. )
  734. /*++
  735. Routine Description:
  736. This routine returns the name of the time zone: equivalent to
  737. this.zone.tzName(this).
  738. Arguments:
  739. None.
  740. Return Value:
  741. Returns the name of the current time zone.
  742. --*/
  743. {
  744. return this.zone.tzName(this);
  745. }
  746. function
  747. dst (
  748. )
  749. /*++
  750. Routine Description:
  751. This routine returns the current offset from UTC time.
  752. Arguments:
  753. None.
  754. Return Value:
  755. Returns a TimeDelta containing the current time zone offset for this
  756. time.
  757. --*/
  758. {
  759. return this.zone.dst(this);
  760. }
  761. function
  762. utcOffset (
  763. )
  764. /*++
  765. Routine Description:
  766. This routine returns the baseline offset from UTC of this timezone.
  767. Arguments:
  768. None.
  769. Return Value:
  770. Returns the equivalent of this.zone.utcOffset(null).
  771. --*/
  772. {
  773. return this.zone.utcOffset(this);
  774. }
  775. function
  776. moveZone (
  777. zone
  778. )
  779. /*++
  780. Routine Description:
  781. This routine returns the equivalent absolute time but with a different
  782. time zone.
  783. Arguments:
  784. Zone - Supplies the new zone to set.
  785. Return Value:
  786. Returns a new Time instance with the same absolute time but a different
  787. time zone.
  788. --*/
  789. {
  790. var utc;
  791. if (this.zone == zone) {
  792. return this;
  793. }
  794. //
  795. // Convert the value to UTC, and then attach this zone.
  796. //
  797. utc = this - this.utcOffset();
  798. utc = utc.replaceZone(zone);
  799. //
  800. // Convert from a UTC time to the zone's local time.
  801. //
  802. return zone.fromUtc(utc);
  803. }
  804. function
  805. timestamp (
  806. )
  807. /*++
  808. Routine Description:
  809. This routine returns the number of seconds since 1970 corresponding to
  810. the given time.
  811. Arguments:
  812. None.
  813. Return Value:
  814. Returns the number of seconds since 1970 corresponding to this date.
  815. --*/
  816. {
  817. var days = this.ordinal() - EPOCH_ORDINAL;
  818. var seconds = (days * 86400);
  819. seconds += (this.hour * 3600) + (this.minute * 60) + this.second;
  820. seconds -= this.utcOffset().totalSeconds();
  821. return seconds;
  822. }
  823. function
  824. compare (
  825. right
  826. )
  827. /*++
  828. Routine Description:
  829. This routine compares two time values in time.
  830. Arguments:
  831. right - Supplies the right side to compare against.
  832. Return Value:
  833. > 0 if this time is greater than the right.
  834. 0 if this time is equal to the right.
  835. < 0 if this time is less than the right.
  836. --*/
  837. {
  838. var difference = this.timestamp() - right.timestamp();
  839. if (difference == 0) {
  840. difference = this.nanosecond - right.nanosecond;
  841. }
  842. return difference;
  843. }
  844. function
  845. tm (
  846. )
  847. /*++
  848. Routine Description:
  849. This routine returns a tm dictionary suitable for use with the lower
  850. level time functions.
  851. Arguments:
  852. None.
  853. Return Value:
  854. returns a tm dictionary.
  855. --*/
  856. {
  857. var dict;
  858. var yearDay;
  859. if (this.year < 1900) {
  860. Core.raise(
  861. ValueError("Cannot create tm dict for years before 1900"));
  862. }
  863. yearDay = monthDays[isLeapYear(this.year)][this.month - 1] +
  864. this.day - 1;
  865. dict = {
  866. "tm_sec": this.second,
  867. "tm_min": this.minute,
  868. "tm_hour": this.hour,
  869. "tm_mday": this.day,
  870. "tm_mon": this.month - 1,
  871. "tm_year": this.year - 1900,
  872. "tm_wday": (this.weekday() + 1) % 7,
  873. "tm_yday": yearDay,
  874. "tm_isdst": this.dst().seconds != 0,
  875. "tm_nanosecond": this.nanosecond,
  876. "tm_gmtoff": this.utcOffset().seconds,
  877. "tm_zone": this.tzName()
  878. };
  879. return dict;
  880. }
  881. function
  882. strftime (
  883. format
  884. )
  885. /*++
  886. Routine Description:
  887. This routine returns a formatted string of the current time.
  888. Arguments:
  889. Supplies the format string. Valid specifiers are:
  890. %a - Replaced by the abbreviated weekday.
  891. %A - Replaced by the full weekday.
  892. %b - Replaced by the abbreviated month name.
  893. %B - Replaced by the full month name.
  894. %c - Replaced by the locale's appropriate date and time
  895. representation.
  896. %C - Replaced by the year divided by 100 (century) [00,99].
  897. %d - Replaced by the day of the month [01,31].
  898. %e - Replaced by the day of the month [ 1,31]. A single digit is
  899. preceded by a space.
  900. %F - Equivalent to "%Y-%m-%d" (the ISO 8601:2001 date format).
  901. %G - The ISO 8601 week-based year [0001,9999]. The week-based year
  902. and the Gregorian year can differ in the first week of January.
  903. %H - Replaced by the 24 hour clock hour [00,23].
  904. %I - Replaced by the 12 hour clock hour [01,12].
  905. %J - Replaced by the nanosecond [0,999999999].
  906. %j - Replaced by the day of the year [001,366].
  907. %m - Replaced by the month number [01,12].
  908. %M - Replaced by the minute [00,59].
  909. %N - Replaced by the microsecond [0,999999]
  910. %n - Replaced by a newline.
  911. %p - Replaced by "AM" or "PM".
  912. %P - Replaced by "am" or "pm".
  913. %q - Replaced by the millisecond [0,999].
  914. %r - Replaced by the time in AM/PM notation: "%I:%M:%S %p".
  915. %R - Replaced by the time in 24 hour notation: "%H:%M".
  916. %S - Replaced by the second [00,60].
  917. %s - Replaced by the number of seconds since 1970 GMT.
  918. %t - Replaced by a tab.
  919. %T - Replaced by the time: "%H:%M:%S".
  920. %u - Replaced by the weekday number, with 1 representing Monday
  921. [1,7].
  922. %V - Replaced by the week number of the year with Monday as the
  923. first day in the week [01,53]. If the week containing January
  924. 1st has 4 or more days in the new year, it is considered week
  925. 1. Otherwise, it is the last week of the previous year, and
  926. the next week is 1.
  927. %w - Replaced by the weekday number [0,6], with 0 representing
  928. Sunday.
  929. %x - Replaced by the locale's appropriate date representation.
  930. %X - Replaced by the locale's appropriate time representation.
  931. %y - Replaced by the last two digits of the year [00,99].
  932. %Y - Replaced by the full four digit year [0001,9999].
  933. %z - Replaced by the offset from UTC in the standard ISO 8601:2000
  934. standard format (+hhmm or -hhmm), or by no characters if no
  935. timezone is terminable. If the "is daylight saving" member of
  936. this calendar structure is greater than zero, then the
  937. daylight saving offset is used. If the dayslight saving member
  938. of the calendar structure is negative, no characters are
  939. returned.
  940. %Z - Replaced by the timezone name or abbreviation, or by no bytes
  941. if no timezone information exists.
  942. %% - Replaced by a literal '%'.
  943. Return Value:
  944. Returns the [year, ISO week, weekday].
  945. --*/
  946. {
  947. var index;
  948. var result = "";
  949. var specifier;
  950. var value;
  951. while (1) {
  952. index = format.indexOf("%");
  953. if (index == -1) {
  954. result += format;
  955. break;
  956. }
  957. result += format[0..index];
  958. specifier = format[index + 1];
  959. if (index == format.length()) {
  960. format = "";
  961. } else {
  962. format = format[(index + 2)...-1];
  963. }
  964. if ((specifier == "a") || (specifier == "A") ||
  965. (specifier == "b") || (specifier == "B") ||
  966. (specifier == "c") ||
  967. (specifier == "x") || (specifier == "X")) {
  968. value = "%" + specifier;
  969. result += (_time.strftime)(value, this.tm());
  970. } else if (specifier == "C") {
  971. result += "%02d" % (this.year / 100);
  972. } else if (specifier == "d") {
  973. result += "%02d" % this.day;
  974. } else if (specifier == "e") {
  975. result += "%2d" % this.day;
  976. } else if (specifier == "F") {
  977. result += "%04d-%02d-%02d" % [this.year, this.month, this.day];
  978. } else if (specifier == "G") {
  979. result += "%04d" % this.isoCalendar()[0];
  980. } else if (specifier == "H") {
  981. result += "%02d" % this.hour;
  982. } else if (specifier == "I") {
  983. value = this.hour;
  984. if (value == 0) {
  985. value = 12;
  986. } else if (value > 12) {
  987. value -= 12;
  988. }
  989. result += "%02d" % value;
  990. } else if (specifier == "J") {
  991. result += "%09d" % this.nanosecond;
  992. } else if (specifier == "j") {
  993. value = monthDays[isLeapYear(this.year)][this.month - 1];
  994. result += "%03d" % value;
  995. } else if (specifier == "m") {
  996. result += "%02d" % this.month;
  997. } else if (specifier == "M") {
  998. result += "%02d" % this.minute;
  999. } else if (specifier == "N") {
  1000. result += "%06d" % (this.nanosecond / 1000);
  1001. } else if (specifier == "n") {
  1002. result += "\n";
  1003. } else if (specifier == "p") {
  1004. if ((this.hour < 12) || (this.hour == 23)) {
  1005. result += "AM";
  1006. } else {
  1007. result += "PM";
  1008. }
  1009. } else if (specifier == "P") {
  1010. if ((this.hour < 12) || (this.hour == 23)) {
  1011. result += "am";
  1012. } else {
  1013. result += "pm";
  1014. }
  1015. } else if (specifier == "q") {
  1016. result += "%03d" % (this.nanosecond / 1000000);
  1017. } else if (specifier == "r") {
  1018. result += this.strftime("%I:%M:%S %p");
  1019. } else if (specifier == "R") {
  1020. result += this.strftime("%H:%M");
  1021. } else if (specifier == "S") {
  1022. result += "%02d" % this.second;
  1023. } else if (specifier == "s") {
  1024. result += "%d" % this.timestamp();
  1025. } else if (specifier == "t") {
  1026. result += "\t";
  1027. } else if (specifier == "T") {
  1028. result += this.strftime("%H:%M:%S");
  1029. } else if (specifier == "u") {
  1030. result += "%d" % this.isoWeekday();
  1031. } else if (specifier == "V") {
  1032. result += "%02d" % this.isoCalendar()[1];
  1033. } else if (specifier == "w") {
  1034. result += "%d" % (this.isoWeekday() % 7);
  1035. } else if (specifier == "x") {
  1036. result += _time.dateString(this.tm());
  1037. } else if (specifier == "X") {
  1038. result += _time.timeString(this.tm());
  1039. } else if (specifier == "y") {
  1040. result += "%02d" % (this.year % 100);
  1041. } else if (specifier == "Y") {
  1042. result += "%04d" % this.year;
  1043. } else if (specifier == "z") {
  1044. value = this.zone.utcOffset(this).totalSeconds() / 60;
  1045. if (value < 0) {
  1046. result += "-";
  1047. value = -value;
  1048. } else {
  1049. result += "+";
  1050. }
  1051. result += "%02d%02d" % [value / 60, value % 60];
  1052. } else if (specifier == "Z") {
  1053. result += this.zone.tzName(this);
  1054. } else if (specifier == "%") {
  1055. result += "%";
  1056. } else {
  1057. Core.raise(FormatError("Invalid specifier '%s'" % specifier));
  1058. }
  1059. }
  1060. return result;
  1061. }
  1062. function
  1063. __str (
  1064. )
  1065. /*++
  1066. Routine Description:
  1067. This routine returns a string of the date, as
  1068. YYYY-MM-DD HH:MM:SS[.nnnnnnnnn] TZ.
  1069. Arguments:
  1070. None.
  1071. Return Value:
  1072. Returns the string representation.
  1073. --*/
  1074. {
  1075. var nanosecond = "";
  1076. if (this.nanosecond != 0) {
  1077. nanosecond = ".%09d" % this.nanosecond;
  1078. }
  1079. return "%04d-%02d-%02d %02d:%02d:%02d%s %s" %
  1080. [this.year,
  1081. this.month,
  1082. this.day,
  1083. this.hour,
  1084. this.minute,
  1085. this.second,
  1086. nanosecond,
  1087. this.zone.__str()];
  1088. }
  1089. function
  1090. __repr (
  1091. )
  1092. /*++
  1093. Routine Description:
  1094. This routine returns a string of the date, as
  1095. Time(y, m, d, h, m, s, ns, z).
  1096. Arguments:
  1097. None.
  1098. Return Value:
  1099. Returns the string representation.
  1100. --*/
  1101. {
  1102. return "Time(%d, %d, %d, %d, %d, %d, %d, %s)" %
  1103. [this.year,
  1104. this.month,
  1105. this.day,
  1106. this.hour,
  1107. this.minute,
  1108. this.second,
  1109. this.nanosecond,
  1110. this.zone.__repr()];
  1111. }
  1112. function
  1113. __add (
  1114. right
  1115. )
  1116. /*++
  1117. Routine Description:
  1118. This routine adds a time delta to a time.
  1119. Arguments:
  1120. right - Supplies the time delta to add.
  1121. Return Value:
  1122. Returns a new time containing the time and time delta.
  1123. --*/
  1124. {
  1125. var result;
  1126. if (!(right is TimeDelta)) {
  1127. Core.raise(TypeError("Expected a TimeDelta"));
  1128. }
  1129. result = Time(this.year,
  1130. this.month,
  1131. this.day,
  1132. this.hour,
  1133. this.minute,
  1134. this.second,
  1135. this.nanosecond,
  1136. this.zone);
  1137. result._set("day", this.day + right.days);
  1138. result._set("second", this.second + right.seconds);
  1139. result._set("nanosecond", this.nanosecond + right.nanoseconds);
  1140. result._normalize();
  1141. return result;
  1142. }
  1143. function
  1144. __sub (
  1145. right
  1146. )
  1147. /*++
  1148. Routine Description:
  1149. This routine subtracts a time delta from this time.
  1150. Arguments:
  1151. right - Supplies the right side to add.
  1152. Return Value:
  1153. Returns a new time containing the adjusted time.
  1154. --*/
  1155. {
  1156. var result;
  1157. if (!(right is TimeDelta)) {
  1158. Core.raise(TypeError("Expected a TimeDelta"));
  1159. }
  1160. result = Time(this.year,
  1161. this.month,
  1162. this.day,
  1163. this.hour,
  1164. this.minute,
  1165. this.second,
  1166. this.nanosecond,
  1167. this.zone);
  1168. result._set("day", this.day - right.days);
  1169. result._set("second", this.second - right.seconds);
  1170. result._set("nanosecond", this.nanosecond - right.nanoseconds);
  1171. result._normalize();
  1172. return result;
  1173. }
  1174. function
  1175. __eq (
  1176. right
  1177. )
  1178. /*++
  1179. Routine Description:
  1180. This routine determines if two time deltas are equal.
  1181. Arguments:
  1182. right - Supplies the right side to compare against.
  1183. Return Value:
  1184. true if the values are equal.
  1185. false if the values are not equal.
  1186. --*/
  1187. {
  1188. if (!(right is Time)) {
  1189. return false;
  1190. }
  1191. return (this.compare(right) == 0) && (this.zone == right.zone);
  1192. }
  1193. function
  1194. __ne (
  1195. right
  1196. )
  1197. /*++
  1198. Routine Description:
  1199. This routine determines if two time deltas are not equal.
  1200. Arguments:
  1201. right - Supplies the right side to compare against.
  1202. Return Value:
  1203. true if the values are not equal.
  1204. false if the values are equal.
  1205. --*/
  1206. {
  1207. return !this.__eq(right);
  1208. }
  1209. function
  1210. _set (
  1211. key,
  1212. value
  1213. )
  1214. /*++
  1215. Routine Description:
  1216. This routine sets a key in the time instance. This routine should only
  1217. be called internally by the Time class.
  1218. Arguments:
  1219. key - Supplies the key to set.
  1220. value - Supplies the value to set.
  1221. Return Value:
  1222. None.
  1223. --*/
  1224. {
  1225. return super.__set(key, value);
  1226. }
  1227. function
  1228. _normalize (
  1229. )
  1230. /*++
  1231. Routine Description:
  1232. This routine normalizes the members of a Time instance.
  1233. Arguments:
  1234. None.
  1235. Return Value:
  1236. None.
  1237. --*/
  1238. {
  1239. var day;
  1240. var daysInMonth;
  1241. var leap;
  1242. var month;
  1243. var ordinal;
  1244. var yearMonthDay;
  1245. this._normalizePair("nanosecond", "second", 1000000000);
  1246. this._normalizePair("second", "minute", 60);
  1247. this._normalizePair("minute", "hour", 60);
  1248. this._normalizePair("hour", "day", 24);
  1249. super.month -= 1;
  1250. this._normalizePair("month", "year", 12);
  1251. month = this.month;
  1252. leap = isLeapYear(this.year);
  1253. daysInMonth = daysPerMonth[leap][month];
  1254. day = this.day;
  1255. if ((day < 1) || (day > daysInMonth)) {
  1256. //
  1257. // Adjusting by a day or so is easier than recomputing from scratch.
  1258. //
  1259. if (day == 0) {
  1260. month -= 1;
  1261. if (month >= 0) {
  1262. day = daysPerMonth[leap][month];
  1263. } else {
  1264. super.year -= 1;
  1265. day = 31;
  1266. month = 11;
  1267. }
  1268. } else if (day == daysInMonth) {
  1269. month += 1;
  1270. day = 1;
  1271. if (month >= 12) {
  1272. month = 0;
  1273. super.year += 1;
  1274. }
  1275. } else {
  1276. ordinal = _dateToOrdinal(this.year, month + 1, 1) + day - 1;
  1277. if ((ordinal < 1) || (ordinal > MAX_ORDINAL)) {
  1278. Core.raise(
  1279. TimeOverflowError("Ordinal %d out of range" % ordinal));
  1280. }
  1281. yearMonthDay = _ordinalToDate(ordinal);
  1282. super.year = yearMonthDay[0];
  1283. month = yearMonthDay[1] - 1;
  1284. day = yearMonthDay[2];
  1285. }
  1286. }
  1287. super.month = month + 1;
  1288. super.day = day;
  1289. return;
  1290. }
  1291. function
  1292. _normalizePair (
  1293. low,
  1294. high,
  1295. factor
  1296. )
  1297. /*++
  1298. Routine Description:
  1299. This routine normalizes two units.
  1300. Arguments:
  1301. low - Supplies the single unit member.
  1302. high - Supplies the member representing factor * low.
  1303. factor - Supplies how many lows go into a high.
  1304. Return Value:
  1305. None.
  1306. --*/
  1307. {
  1308. var highCount;
  1309. var lowValue = this.__get(low);
  1310. if ((lowValue < 0) || (lowValue >= factor)) {
  1311. highCount = lowValue / factor;
  1312. lowValue = lowValue - (highCount * factor);
  1313. if (lowValue < 0) {
  1314. highCount -= 1;
  1315. lowValue += factor;
  1316. }
  1317. highCount += this.__get(high);
  1318. super.__set(low, lowValue);
  1319. super.__set(high, highCount);
  1320. }
  1321. return;
  1322. }
  1323. }
  1324. //
  1325. // The TimeZone class is an abstract class defining a time zone.
  1326. //
  1327. class TimeZone {
  1328. function
  1329. utcOffset (
  1330. time
  1331. )
  1332. /*++
  1333. Routine Description:
  1334. This routine returns the offset from UTC to local time, in minutes
  1335. east of UTC. Most implementations will probably return either a
  1336. constant, or a constant plus this.dst(time).
  1337. Arguments:
  1338. time - Supplies an optional time.
  1339. Return Value:
  1340. Returns a TimeDelta containing the offset from UTC for the given date.
  1341. --*/
  1342. {
  1343. Core.raise(TimeZoneNotImplemented("utcOffset not implemented"));
  1344. }
  1345. function
  1346. dst (
  1347. time
  1348. )
  1349. /*++
  1350. Routine Description:
  1351. This routine returns the daylight saving time adjustment for the given
  1352. time.
  1353. Arguments:
  1354. time - Supplies the time.
  1355. Return Value:
  1356. Returns a TimeDelta containing the DST adjustment for the given time.
  1357. --*/
  1358. {
  1359. Core.raise(TimeZoneNotImplemented("dst not implemented"));
  1360. }
  1361. function
  1362. tzName (
  1363. time
  1364. )
  1365. /*++
  1366. Routine Description:
  1367. This routine returns the name for the current time zone.
  1368. Arguments:
  1369. time - Supplies the time.
  1370. Return Value:
  1371. Returns an arbitrary string naming the time zone.
  1372. --*/
  1373. {
  1374. Core.raise(TimeZoneNotImplemented("tzName not implemented"));
  1375. }
  1376. function
  1377. fromUtc (
  1378. time
  1379. )
  1380. /*++
  1381. Routine Description:
  1382. This routine adjusts a time specified in UTC time into local time.
  1383. Most time zone implementations can accept the default implementation
  1384. here.
  1385. Arguments:
  1386. time - Supplies the time.
  1387. Return Value:
  1388. Returns the adjusted time.
  1389. --*/
  1390. {
  1391. var delta;
  1392. var timeDst = time.dst();
  1393. if (time.zone != this) {
  1394. Core.raise(ValueError("Adjusting across different time zones"));
  1395. }
  1396. //
  1397. // Get the standard offset.
  1398. //
  1399. delta = time.utcOffset() - timeDst;
  1400. if (delta.totalSeconds() != 0) {
  1401. time += delta;
  1402. timeDst = time.dst();
  1403. }
  1404. if (timeDst.totalSeconds() != 0) {
  1405. return time + timeDst;
  1406. }
  1407. return time;
  1408. }
  1409. function
  1410. __str (
  1411. )
  1412. /*++
  1413. Routine Description:
  1414. This routine returns the string form of the given time zone. This
  1415. implementation just returns this.tzName().
  1416. Arguments:
  1417. None.
  1418. Return Value:
  1419. Returns the time zone name.
  1420. --*/
  1421. {
  1422. return this.tzName(null);
  1423. }
  1424. }
  1425. //
  1426. // Default time zone class implementations
  1427. //
  1428. class FixedTimeZone is TimeZone {
  1429. var _dst;
  1430. var _offset;
  1431. var _name;
  1432. function
  1433. __init (
  1434. minutes,
  1435. name
  1436. )
  1437. /*++
  1438. Routine Description:
  1439. This routine initializes a fixed time zone.
  1440. Arguments:
  1441. None.
  1442. Return Value:
  1443. Returns this.
  1444. --*/
  1445. {
  1446. _offset = TimeDelta(0, minutes * 60, 0);
  1447. _dst = TimeDelta(0, 0, 0);
  1448. _name = name;
  1449. return this;
  1450. }
  1451. function
  1452. utcOffset (
  1453. time
  1454. )
  1455. /*++
  1456. Routine Description:
  1457. This routine returns the offset from UTC to local time, in minutes
  1458. east of UTC. Most implementations will probably return either a
  1459. constant, or a constant plus this.dst(time).
  1460. Arguments:
  1461. time - Supplies an optional time.
  1462. Return Value:
  1463. Returns a TimeDelta containing the offset from UTC for the given date.
  1464. --*/
  1465. {
  1466. return _offset;
  1467. }
  1468. function
  1469. dst (
  1470. time
  1471. )
  1472. /*++
  1473. Routine Description:
  1474. This routine returns the daylight saving time adjustment for the given
  1475. time.
  1476. Arguments:
  1477. time - Supplies the time.
  1478. Return Value:
  1479. Returns a TimeDelta containing the DST adjustment for the given time.
  1480. --*/
  1481. {
  1482. return _dst;
  1483. }
  1484. function
  1485. tzName (
  1486. time
  1487. )
  1488. /*++
  1489. Routine Description:
  1490. This routine returns the name for the current time zone.
  1491. Arguments:
  1492. time - Supplies the time.
  1493. Return Value:
  1494. Returns an arbitrary string naming the time zone.
  1495. --*/
  1496. {
  1497. return _name;
  1498. }
  1499. }
  1500. class UTC is FixedTimeZone {
  1501. function
  1502. __init (
  1503. )
  1504. /*++
  1505. Routine Description:
  1506. This routine initializes a UTC time zone instance.
  1507. Arguments:
  1508. None.
  1509. Return Value:
  1510. Returns this.
  1511. --*/
  1512. {
  1513. return super.__init(0, "UTC");
  1514. }
  1515. function
  1516. __repr (
  1517. )
  1518. /*++
  1519. Routine Description:
  1520. This routine returns the representation of the UTC time zone.
  1521. Arguments:
  1522. None.
  1523. Return Value:
  1524. Returns this.
  1525. --*/
  1526. {
  1527. return "UTC()";
  1528. }
  1529. }
  1530. class LocalTimeZone is TimeZone {
  1531. var _std;
  1532. var _dst;
  1533. var _dstDifference;
  1534. var _zero;
  1535. function
  1536. __init (
  1537. )
  1538. /*++
  1539. Routine Description:
  1540. This routine initializes a time zone instance that matches the platform.
  1541. Arguments:
  1542. None.
  1543. Return Value:
  1544. Returns this.
  1545. --*/
  1546. {
  1547. var now;
  1548. var tm;
  1549. var utcTime;
  1550. _zero = TimeDelta();
  1551. _std = TimeDelta(0, -_time.timezone, 0);
  1552. if (_time.daylight) {
  1553. //
  1554. // Find a time where daylight saving is set. Start with now.
  1555. //
  1556. now = (_time.time)();
  1557. tm = (_time.localtime)(now);
  1558. if (!tm.tm_isdst) {
  1559. //
  1560. // Try adding a month to the time until is_dst flips.
  1561. //
  1562. for (month in 0..12) {
  1563. now += 3600 * 24 * 30;
  1564. tm = (_time.localtime)(now);
  1565. if (tm.tm_isdst) {
  1566. break;
  1567. }
  1568. }
  1569. }
  1570. //
  1571. // If tm_isdst weirdly never flipped, then it's all constant.
  1572. //
  1573. if (!tm.tm_isdst) {
  1574. _dst = _std;
  1575. //
  1576. // Create the same time in UTC and see how its timestamp differs
  1577. // from the one that set isdst in local time.
  1578. //
  1579. } else {
  1580. utcTime = Time(tm.tm_year + 1900,
  1581. tm.tm_mon + 1,
  1582. tm.tm_mday,
  1583. tm.tm_hour,
  1584. tm.tm_min,
  1585. tm.tm_sec,
  1586. 0,
  1587. UTC());
  1588. _dst = TimeDelta(0, utcTime.timestamp() - now, 0);
  1589. }
  1590. } else {
  1591. _dst = _std;
  1592. }
  1593. _dstDifference = _dst - _std;
  1594. return this;
  1595. }
  1596. function
  1597. utcOffset (
  1598. time
  1599. )
  1600. /*++
  1601. Routine Description:
  1602. This routine returns the offset from UTC to local time, in minutes
  1603. east of UTC. Most implementations will probably return either a
  1604. constant, or a constant plus this.dst(time).
  1605. Arguments:
  1606. time - Supplies an optional time.
  1607. Return Value:
  1608. Returns a TimeDelta containing the offset from UTC for the given date.
  1609. --*/
  1610. {
  1611. if (this._isDst(time)) {
  1612. return _dst;
  1613. }
  1614. return _std;
  1615. }
  1616. function
  1617. dst (
  1618. time
  1619. )
  1620. /*++
  1621. Routine Description:
  1622. This routine returns the daylight saving time adjustment for the given
  1623. time.
  1624. Arguments:
  1625. time - Supplies the time.
  1626. Return Value:
  1627. Returns a TimeDelta containing the DST adjustment for the given time.
  1628. --*/
  1629. {
  1630. if (this._isDst(time)) {
  1631. return _dstDifference;
  1632. }
  1633. return _zero;
  1634. }
  1635. function
  1636. tzName (
  1637. time
  1638. )
  1639. /*++
  1640. Routine Description:
  1641. This routine returns the name for the current time zone.
  1642. Arguments:
  1643. time - Supplies the time.
  1644. Return Value:
  1645. Returns an arbitrary string naming the time zone.
  1646. --*/
  1647. {
  1648. return _time.tzname[this._isDst(time)];
  1649. }
  1650. function
  1651. _isDst (
  1652. time
  1653. )
  1654. /*++
  1655. Routine Description:
  1656. This routine determines if the given time is in the platform's Daylight
  1657. time or regular time.
  1658. Arguments:
  1659. time - Supplies the time.
  1660. Return Value:
  1661. false if the time is in standard time.
  1662. true if the time is in daylight time.
  1663. --*/
  1664. {
  1665. var localtm;
  1666. var timestamp;
  1667. var tm;
  1668. if (time == null) {
  1669. return false;
  1670. }
  1671. //
  1672. // Manually create a tm dict because the real tm function calls
  1673. // utcOffset and dst, which would cause infinite recursion.
  1674. //
  1675. tm = {
  1676. "tm_sec": time.second,
  1677. "tm_min": time.minute,
  1678. "tm_hour": time.hour,
  1679. "tm_mday": time.day,
  1680. "tm_mon": time.month - 1,
  1681. "tm_year": time.year - 1900,
  1682. "tm_wday": (time.weekday() + 1) % 7,
  1683. };
  1684. timestamp = (_time.mktime)(tm);
  1685. localtm = (_time.localtime)(timestamp);
  1686. return localtm.tm_isdst;
  1687. }
  1688. function
  1689. __repr (
  1690. )
  1691. /*++
  1692. Routine Description:
  1693. This routine returns the representation of the UTC time zone.
  1694. Arguments:
  1695. None.
  1696. Return Value:
  1697. Returns this.
  1698. --*/
  1699. {
  1700. return "LocalTimeZone()";
  1701. }
  1702. }
  1703. //
  1704. // --------------------------------------------------------- Internal Functions
  1705. //
  1706. function
  1707. _dateToOrdinal (
  1708. year,
  1709. month,
  1710. day
  1711. )
  1712. /*++
  1713. Routine Description:
  1714. This routine converts a year, month, and date into an ordinal day (number
  1715. of days since 1/1/0001).
  1716. Arguments:
  1717. None.
  1718. Return Value:
  1719. Returns the ordinal day of the year.
  1720. --*/
  1721. {
  1722. return _daysBeforeYear(year) + _daysBeforeMonth(year, month) + day;
  1723. }
  1724. function
  1725. _ordinalToDate (
  1726. ordinal
  1727. )
  1728. /*++
  1729. Routine Description:
  1730. This routine converts a number of days since January 1, 0001 into a year,
  1731. month, and day.
  1732. Arguments:
  1733. ordinal - Returns the number of days since January 1, 0001, pretending that
  1734. the Gregorian calendar went back that far.
  1735. Return Value:
  1736. Returns a list containing the [year, month, day] for the given ordinal.
  1737. January is month 1.
  1738. --*/
  1739. {
  1740. var cycle1;
  1741. var cycle4;
  1742. var cycle100;
  1743. var cycle400;
  1744. var leap;
  1745. var month;
  1746. var daysBefore;
  1747. var result = [0, 0, 0];
  1748. var value;
  1749. //
  1750. // Subtract 1 to get on the 400 year rotation.
  1751. //
  1752. ordinal -= 1;
  1753. cycle400 = ordinal / DAYS_IN_400_YEARS;
  1754. value = ordinal % DAYS_IN_400_YEARS;
  1755. cycle100 = value / DAYS_IN_100_YEARS;
  1756. value %= DAYS_IN_100_YEARS;
  1757. cycle4 = value / DAYS_IN_4_YEARS;
  1758. value %= DAYS_IN_4_YEARS;
  1759. cycle1 = value / 365;
  1760. value %= 365;
  1761. result[0] = (cycle400 * 400) + 1 + (cycle100 * 100) + (cycle4 * 4) + cycle1;
  1762. if ((cycle1 == 4) && (cycle100 == 4)) {
  1763. result[0] -= 1;
  1764. result[1] = 12;
  1765. result[2] = 31;
  1766. return result;
  1767. }
  1768. //
  1769. // To figure out the month and day, take a guess that might be too large
  1770. // and will never be too small), and back off if so.
  1771. //
  1772. leap = (cycle1 == 3) && ((cycle4 != 24) || (cycle100 == 3));
  1773. month = ((value + 50) >> 5) - 1;
  1774. daysBefore = monthDays[leap][month];
  1775. if (daysBefore > value) {
  1776. month -= 1;
  1777. daysBefore = monthDays[leap][month];
  1778. }
  1779. result[1] = month + 1;
  1780. result[2] = value - daysBefore + 1;
  1781. return result;
  1782. }
  1783. function
  1784. _isoWeek1 (
  1785. year
  1786. )
  1787. /*++
  1788. Routine Description:
  1789. This routine returns the ordinal number of the Monday starting week 1 of
  1790. the given ISO year. The first ISO week of the year is the first week that
  1791. contains a Thursday.
  1792. Arguments:
  1793. year - Supplies the year.
  1794. Return Value:
  1795. Returns the ordinal number of the start of the given ISO year.
  1796. --*/
  1797. {
  1798. var firstDay = _dateToOrdinal(year, 1, 1);
  1799. var firstMonday;
  1800. var firstWeekday = (firstDay + 6) % 7;
  1801. firstMonday = firstDay - firstWeekday;
  1802. if (firstWeekday > 3) {
  1803. firstMonday += 7;
  1804. }
  1805. return firstMonday;
  1806. }
  1807. function
  1808. _daysBeforeYear (
  1809. year
  1810. )
  1811. /*++
  1812. Routine Description:
  1813. This routine returns the number of days between January 1, 0001, and
  1814. January 1 of the given year (pretending the Gregorian calendar stretched
  1815. that far back).
  1816. Arguments:
  1817. year - Supplies the year to convert.
  1818. Return Value:
  1819. Returns the number of days between January 1, 0001, and the start of the
  1820. given year.
  1821. --*/
  1822. {
  1823. //
  1824. // Subtract 1 to get even with the 400 year cycle (which starts on year 1).
  1825. //
  1826. year -= 1;
  1827. return (year * 365) + (year / 4) - (year / 100) + (year / 400);
  1828. }
  1829. function
  1830. _daysBeforeMonth (
  1831. year,
  1832. month
  1833. )
  1834. /*++
  1835. Routine Description:
  1836. This routine returns the number of days that occurred between the start of
  1837. the year and the given month.
  1838. Arguments:
  1839. year - Supplies the year to check, since it matters whether or not that
  1840. year was a leap year.
  1841. month - Supplies the month to check. January is 1.
  1842. Return Value:
  1843. Returns the number of days between January 1st of the given year and the
  1844. 1st of the given month.
  1845. --*/
  1846. {
  1847. return monthDays[isLeapYear(year)][month - 1];
  1848. }
  1849. //
  1850. // Instantiate the two main time zones.
  1851. //
  1852. utc = UTC();
  1853. localTime = LocalTimeZone();