/src/moddable/xs/sources/xsDate.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2016-2025 Moddable Tech, Inc. |
3 | | * |
4 | | * This file is part of the Moddable SDK Runtime. |
5 | | * |
6 | | * The Moddable SDK Runtime is free software: you can redistribute it and/or modify |
7 | | * it under the terms of the GNU Lesser General Public License as published by |
8 | | * the Free Software Foundation, either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * The Moddable SDK Runtime is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public License |
17 | | * along with the Moddable SDK Runtime. If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | * This file incorporates work covered by the following copyright and |
20 | | * permission notice: |
21 | | * |
22 | | * Copyright (C) 2010-2016 Marvell International Ltd. |
23 | | * Copyright (C) 2002-2010 Kinoma, Inc. |
24 | | * |
25 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
26 | | * you may not use this file except in compliance with the License. |
27 | | * You may obtain a copy of the License at |
28 | | * |
29 | | * http://www.apache.org/licenses/LICENSE-2.0 |
30 | | * |
31 | | * Unless required by applicable law or agreed to in writing, software |
32 | | * distributed under the License is distributed on an "AS IS" BASIS, |
33 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
34 | | * See the License for the specific language governing permissions and |
35 | | * limitations under the License. |
36 | | */ |
37 | | |
38 | | #include "xsAll.h" |
39 | | |
40 | | typedef struct sxDateTime { |
41 | | txNumber year; |
42 | | txNumber month; |
43 | | txNumber date; |
44 | | txNumber hours; |
45 | | txNumber minutes; |
46 | | txNumber seconds; |
47 | | txNumber milliseconds; |
48 | | txInteger day; |
49 | | txInteger offset; |
50 | | txNumber value; |
51 | | } txDateTime; |
52 | | |
53 | | static txSlot* fxNewDateInstance(txMachine* the); |
54 | | |
55 | | static void fx_Date_aux(txMachine* the, txFlag secure); |
56 | | static txInteger fx_Date_parse_number(txByte* theCharacter, txString* theString, txBoolean* overflow); |
57 | | static txInteger fx_Date_parse_fraction(txByte* theCharacter, txString* theString); |
58 | | static txBoolean fx_Date_prototype_get_aux(txMachine* the, txDateTime* td, txBoolean utc, txSlot* slot); |
59 | | static void fx_Date_prototype_set_aux(txMachine* the, txDateTime* td, txBoolean utc, txSlot* slot); |
60 | | |
61 | | static txSlot* fxDateCheck(txMachine* the); |
62 | | static txNumber fxDateClip(txNumber value); |
63 | | static txNumber fxDateFullYear(txMachine* the, txSlot* slot); |
64 | | static txNumber fxDateMerge(txDateTime* dt, txBoolean utc); |
65 | | static txString fxDatePrint2Digits(txString p, txInteger value); |
66 | | static txString fxDatePrint3Digits(txString p, txInteger value); |
67 | | static txString fxDatePrint4Digits(txString p, txInteger value); |
68 | | static txString fxDatePrintDate(txString p, txInteger year, txInteger month, txInteger date); |
69 | | static txString fxDatePrintDateUTC(txString p, txInteger year, txInteger month, txInteger date); |
70 | | static txString fxDatePrintDay(txString p, txInteger day); |
71 | | static txString fxDatePrintTime(txString p, txInteger hours, txInteger minutes, txInteger seconds); |
72 | | static txString fxDatePrintTimezone(txString p, txInteger offset); |
73 | | static txString fxDatePrintYear(txString p, txInteger value); |
74 | | static txInteger fxDateSimilarYear(txInteger year); |
75 | | static void fxDateSplit(txNumber value, txBoolean utc, txDateTime* dt); |
76 | | |
77 | | void fxBuildDate(txMachine* the) |
78 | 38.0k | { |
79 | 38.0k | txSlot* slot; |
80 | 38.0k | mxPush(mxObjectPrototype); |
81 | 38.0k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
82 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMilliseconds), 0, mxID(_getMilliseconds), XS_DONT_ENUM_FLAG); |
83 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getSeconds), 0, mxID(_getSeconds), XS_DONT_ENUM_FLAG); |
84 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMinutes), 0, mxID(_getMinutes), XS_DONT_ENUM_FLAG); |
85 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getHours), 0, mxID(_getHours), XS_DONT_ENUM_FLAG); |
86 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDay), 0, mxID(_getDay), XS_DONT_ENUM_FLAG); |
87 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDate), 0, mxID(_getDate), XS_DONT_ENUM_FLAG); |
88 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMonth), 0, mxID(_getMonth), XS_DONT_ENUM_FLAG); |
89 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getYear), 0, mxID(_getYear), XS_DONT_ENUM_FLAG); |
90 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getFullYear), 0, mxID(_getFullYear), XS_DONT_ENUM_FLAG); |
91 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMilliseconds), 0, mxID(_getUTCMilliseconds), XS_DONT_ENUM_FLAG); |
92 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCSeconds), 0, mxID(_getUTCSeconds), XS_DONT_ENUM_FLAG); |
93 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMinutes), 0, mxID(_getUTCMinutes), XS_DONT_ENUM_FLAG); |
94 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCHours), 0, mxID(_getUTCHours), XS_DONT_ENUM_FLAG); |
95 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDay), 0, mxID(_getUTCDay), XS_DONT_ENUM_FLAG); |
96 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDate), 0, mxID(_getUTCDate), XS_DONT_ENUM_FLAG); |
97 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMonth), 0, mxID(_getUTCMonth), XS_DONT_ENUM_FLAG); |
98 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCFullYear), 0, mxID(_getUTCFullYear), XS_DONT_ENUM_FLAG); |
99 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_getTime), XS_DONT_ENUM_FLAG); |
100 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getTimezoneOffset), 0, mxID(_getTimezoneOffset), XS_DONT_ENUM_FLAG); |
101 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setDate), 1, mxID(_setDate), XS_DONT_ENUM_FLAG); |
102 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setFullYear), 3, mxID(_setFullYear), XS_DONT_ENUM_FLAG); |
103 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setHours), 4, mxID(_setHours), XS_DONT_ENUM_FLAG); |
104 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMilliseconds), 1, mxID(_setMilliseconds), XS_DONT_ENUM_FLAG); |
105 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMinutes), 3, mxID(_setMinutes), XS_DONT_ENUM_FLAG); |
106 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMonth), 2, mxID(_setMonth), XS_DONT_ENUM_FLAG); |
107 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setSeconds), 2, mxID(_setSeconds), XS_DONT_ENUM_FLAG); |
108 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setTime), 1, mxID(_setTime), XS_DONT_ENUM_FLAG); |
109 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setYear), 1, mxID(_setYear), XS_DONT_ENUM_FLAG); |
110 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCDate), 1, mxID(_setUTCDate), XS_DONT_ENUM_FLAG); |
111 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCFullYear), 3, mxID(_setUTCFullYear), XS_DONT_ENUM_FLAG); |
112 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCHours), 4, mxID(_setUTCHours), XS_DONT_ENUM_FLAG); |
113 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMilliseconds), 1, mxID(_setUTCMilliseconds), XS_DONT_ENUM_FLAG); |
114 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMinutes), 3, mxID(_setUTCMinutes), XS_DONT_ENUM_FLAG); |
115 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMonth), 2, mxID(_setUTCMonth), XS_DONT_ENUM_FLAG); |
116 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCSeconds), 2, mxID(_setUTCSeconds), XS_DONT_ENUM_FLAG); |
117 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toDateString), XS_DONT_ENUM_FLAG); |
118 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toISOString), 0, mxID(_toISOString), XS_DONT_ENUM_FLAG); |
119 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toJSON), 1, mxID(_toJSON), XS_DONT_ENUM_FLAG); |
120 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toLocaleDateString), XS_DONT_ENUM_FLAG); |
121 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toLocaleString), XS_DONT_ENUM_FLAG); |
122 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toLocaleTimeString), XS_DONT_ENUM_FLAG); |
123 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG); |
124 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toTimeString), XS_DONT_ENUM_FLAG); |
125 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toUTCString), 0, mxID(_toUTCString), XS_DONT_ENUM_FLAG); |
126 | 38.0k | slot = fxNextSlotProperty(the, slot, slot, mxID(_toGMTString), XS_DONT_ENUM_FLAG); |
127 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_valueOf), XS_DONT_ENUM_FLAG); |
128 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toPrimitive), 1, mxID(_Symbol_toPrimitive), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
129 | 38.0k | mxDatePrototype = *the->stack; |
130 | 38.0k | slot = fxBuildHostConstructor(the, mxCallback(fx_Date), 7, mxID(_Date)); |
131 | 38.0k | mxDateConstructor = *the->stack; |
132 | 38.0k | slot = fxLastProperty(the, slot); |
133 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_now), 0, mxID(_now), XS_DONT_ENUM_FLAG); |
134 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_parse), 1, mxID(_parse), XS_DONT_ENUM_FLAG); |
135 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_UTC), 7, mxID(_UTC), XS_DONT_ENUM_FLAG); |
136 | 38.0k | mxPop(); |
137 | 38.0k | } |
138 | | |
139 | | txSlot* fxNewDateInstance(txMachine* the) |
140 | 214k | { |
141 | 214k | txSlot* instance; |
142 | 214k | txSlot* property; |
143 | 214k | instance = fxNewObjectInstance(the); |
144 | 214k | property = fxNextNumberProperty(the, instance, 0, XS_NO_ID, XS_INTERNAL_FLAG); |
145 | 214k | property->kind = XS_DATE_KIND; |
146 | 214k | property->value.number = C_NAN; |
147 | 214k | return instance; |
148 | 214k | } |
149 | | |
150 | | void fx_Date(txMachine* the) |
151 | 235k | { |
152 | 235k | fx_Date_aux(the, 0); |
153 | 235k | } |
154 | | |
155 | | void fx_Date_aux(txMachine* the, txFlag secure) |
156 | 235k | { |
157 | 235k | txInteger c = mxArgc; |
158 | 235k | txDateTime dt; |
159 | 235k | txSlot* instance; |
160 | 235k | if (mxIsUndefined(mxTarget)) { |
161 | 20.4k | char buffer[256]; |
162 | 20.4k | txString p = buffer; |
163 | 20.4k | txDateTime dt; |
164 | 20.4k | if (secure) |
165 | 0 | mxTypeError("secure mode"); |
166 | 20.4k | mxResult->value.number = fxDateNow(); |
167 | 20.4k | mxResult->kind = XS_NUMBER_KIND; |
168 | 20.4k | fxDateSplit(mxResult->value.number, 0, &dt); |
169 | 20.4k | p = fxDatePrintDay(p, dt.day); |
170 | 20.4k | *p++ = ' '; |
171 | 20.4k | p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date); |
172 | 20.4k | *p++ = ' '; |
173 | 20.4k | p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds); |
174 | 20.4k | *p++ = ' '; |
175 | 20.4k | p = fxDatePrintTimezone(p, (txInteger)dt.offset); |
176 | 20.4k | *p = 0; |
177 | 20.4k | fxCopyStringC(the, mxResult, buffer); |
178 | 20.4k | return; |
179 | 20.4k | } |
180 | 214k | mxPushSlot(mxTarget); |
181 | 214k | fxGetPrototypeFromConstructor(the, &mxDatePrototype); |
182 | 214k | instance = fxNewDateInstance(the); |
183 | 214k | mxPullSlot(mxResult); |
184 | 214k | if (c > 1) { |
185 | 32.2k | dt.year = fxDateFullYear(the, mxArgv(0)); |
186 | 32.2k | dt.month = fxToNumber(the, mxArgv(1)); |
187 | 32.2k | dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1; |
188 | 32.2k | dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0; |
189 | 32.2k | dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0; |
190 | 32.2k | dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0; |
191 | 32.2k | dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0; |
192 | 32.2k | instance->next->value.number = fxDateMerge(&dt, 0); |
193 | 32.2k | return; |
194 | 32.2k | } |
195 | 182k | if (c > 0) { |
196 | 178k | txSlot* slot = mxArgv(0); |
197 | 178k | if (slot->kind == XS_REFERENCE_KIND) { |
198 | 2.62k | txSlot* date = slot->value.reference; |
199 | 2.62k | if ((date->next) && (date->next->kind == XS_DATE_KIND)) { |
200 | 211 | instance->next->value.number = date->next->value.number; |
201 | 211 | return; |
202 | 211 | } |
203 | 2.62k | } |
204 | 178k | fxToPrimitive(the, slot, XS_NO_HINT); |
205 | 178k | if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) { |
206 | 17.9k | mxPushSlot(mxFunction); |
207 | 17.9k | mxDub(); |
208 | 17.9k | mxGetID(mxID(_parse)); |
209 | 17.9k | mxCall(); |
210 | 17.9k | mxPushSlot(slot); |
211 | 17.9k | mxRunCount(1); |
212 | 17.9k | instance->next->value.number = the->stack->value.number; |
213 | 17.9k | mxPop(); |
214 | 17.9k | return; |
215 | 17.9k | } |
216 | 160k | instance->next->value.number = fxDateClip(fxToNumber(the, slot)); |
217 | 160k | return; |
218 | 178k | } |
219 | 3.57k | if (secure) |
220 | 0 | mxTypeError("secure mode"); |
221 | 3.57k | instance->next->value.number = fxDateNow(); |
222 | 3.57k | } |
223 | | |
224 | | void fx_Date_secure(txMachine* the) |
225 | 0 | { |
226 | 0 | fx_Date_aux(the, 1); |
227 | 0 | } |
228 | | |
229 | | void fx_Date_now(txMachine* the) |
230 | 3 | { |
231 | 3 | mxResult->value.number = fxDateNow(); |
232 | 3 | mxResult->kind = XS_NUMBER_KIND; |
233 | 3 | } |
234 | | |
235 | | void fx_Date_now_secure(txMachine* the) |
236 | 0 | { |
237 | 0 | mxTypeError("secure mode"); |
238 | 0 | } |
239 | | |
240 | | txInteger fx_Date_parse_number(txByte* theCharacter, txString* theString, txBoolean* overflow) |
241 | 756k | { |
242 | 756k | txByte c = *theCharacter; |
243 | 756k | txString p = *theString; |
244 | 756k | txInteger aResult = c - '0'; |
245 | 756k | c = c_read8(p++); |
246 | 1.53M | while (('0' <= c) && (c <= '9')) { |
247 | 778k | #if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_mul_overflow) |
248 | 778k | if (__builtin_mul_overflow(aResult, 10, &aResult) || |
249 | 736k | __builtin_add_overflow(aResult, c - '0', &aResult)) |
250 | 53.1k | *overflow = 1; |
251 | | #else |
252 | | aResult = (aResult * 10) + c - '0'; |
253 | | if (aResult < 0) |
254 | | *overflow = 1; |
255 | | #endif |
256 | 778k | c = c_read8(p++); |
257 | 778k | } |
258 | 756k | *theCharacter = c; |
259 | 756k | *theString = p; |
260 | 756k | return aResult; |
261 | 756k | } |
262 | | |
263 | | txInteger fx_Date_parse_fraction(txByte* theCharacter, txString* theString) |
264 | 2.96k | { |
265 | 2.96k | txByte c = *theCharacter; |
266 | 2.96k | txString p = *theString; |
267 | 2.96k | txNumber fraction = 100; |
268 | 2.96k | txNumber aResult = ((c - '0') * fraction); |
269 | 2.96k | c = c_read8(p++); |
270 | 6.31k | while (('0' <= c) && (c <= '9')) { |
271 | 3.35k | fraction /= 10; |
272 | 3.35k | aResult = aResult + ((c - '0') * fraction); |
273 | 3.35k | c = c_read8(p++); |
274 | 3.35k | } |
275 | 2.96k | *theCharacter = c; |
276 | 2.96k | *theString = p; |
277 | 2.96k | return (txInteger)c_trunc(aResult); |
278 | 2.96k | } |
279 | | |
280 | | void fx_Date_parse(txMachine* the) |
281 | 930k | { |
282 | 4.60M | #define mxDayCount 7 |
283 | 930k | static const char* const gxDays[mxDayCount] ICACHE_RODATA_ATTR = { |
284 | 930k | "monday", |
285 | 930k | "tuesday", |
286 | 930k | "wednesday", |
287 | 930k | "thursday", |
288 | 930k | "friday", |
289 | 930k | "saturday", |
290 | 930k | "sunday" |
291 | 930k | }; |
292 | 7.04M | #define mxMonthCount 12 |
293 | 930k | static const char* const gxMonths[mxMonthCount] ICACHE_RODATA_ATTR = { |
294 | 930k | "january", |
295 | 930k | "february", |
296 | 930k | "march", |
297 | 930k | "april", |
298 | 930k | "may", |
299 | 930k | "june", |
300 | 930k | "july", |
301 | 930k | "august", |
302 | 930k | "september", |
303 | 930k | "october", |
304 | 930k | "november", |
305 | 930k | "december" |
306 | 930k | }; |
307 | 6.33M | #define mxZoneCount 11 |
308 | 930k | static const char* const gxZones[mxZoneCount] ICACHE_RODATA_ATTR = { |
309 | 930k | "gmt", "ut", "utc", |
310 | 930k | "est", "edt", |
311 | 930k | "cst", "cdt", |
312 | 930k | "mst", "mdt", |
313 | 930k | "pst", "pdt" |
314 | 930k | }; |
315 | 930k | static const int gxDeltas[mxZoneCount] ICACHE_XS6RO2_ATTR = { |
316 | 930k | 0, 0, 0, |
317 | 930k | -5, -4, |
318 | 930k | -6, -5, |
319 | 930k | -7, -6, |
320 | 930k | -8, -7 |
321 | 930k | }; |
322 | | |
323 | 930k | txString aString; |
324 | 930k | txBoolean overflow = 0; |
325 | 930k | txDateTime dt; |
326 | 930k | txString p; |
327 | 930k | txString q; |
328 | 930k | txByte c; |
329 | 930k | char buffer[10]; /* base type should be the same as txString */ |
330 | 930k | txInteger aComment; |
331 | 930k | txInteger aDelta; |
332 | 930k | txInteger aValue; |
333 | 930k | txSize aLength; |
334 | 930k | txInteger i; |
335 | 930k | txInteger yearSign = 1; |
336 | | |
337 | 930k | if (mxArgc < 1) |
338 | 1 | goto fail; |
339 | 930k | aString = fxToString(the, mxArgv(0)); |
340 | | |
341 | 930k | dt.seconds = -1; |
342 | 930k | dt.minutes = -1; |
343 | 930k | dt.hours = -1; |
344 | 930k | dt.date = -1; |
345 | 930k | dt.month = -1; |
346 | 930k | dt.year = -1; |
347 | 930k | dt.milliseconds = -1; |
348 | 930k | aComment = 0; |
349 | 930k | aDelta = -1; |
350 | | |
351 | 930k | c = c_read8(aString++); |
352 | 8.54M | while (c) { |
353 | 8.53M | if (c == '(') { |
354 | 2.67k | aComment++; |
355 | 2.67k | c = c_read8(aString++); |
356 | 2.67k | continue; |
357 | 2.67k | } |
358 | 8.52M | else if (c == ')') { |
359 | 6.30k | if (aComment) { |
360 | 1.84k | aComment--; |
361 | 1.84k | c = c_read8(aString++); |
362 | 1.84k | continue; |
363 | 1.84k | } |
364 | 4.45k | else |
365 | 4.45k | goto fail; |
366 | 6.30k | } |
367 | 8.52M | else if (aComment) { |
368 | 44.3k | c = c_read8(aString++); |
369 | 44.3k | continue; |
370 | 44.3k | } |
371 | | |
372 | 8.47M | if ((c <= ' ') || (c == ',')) { |
373 | 7.01M | c = c_read8(aString++); |
374 | 7.01M | continue; |
375 | 7.01M | } |
376 | | |
377 | 1.46M | else if ((c == '-') | (c == '+')) { |
378 | 31.1k | txInteger aSign; |
379 | 31.1k | if (c == '-') |
380 | 29.0k | aSign = -1; |
381 | 2.09k | else |
382 | 2.09k | aSign = 1; |
383 | 31.1k | c = c_read8(aString++); |
384 | 31.1k | if (('0' <= c) && (c <= '9')) { |
385 | 30.2k | aValue = fx_Date_parse_number(&c, &aString, &overflow); |
386 | 30.2k | if (c == '-') { |
387 | 9.53k | if (dt.year >= 0) |
388 | 1.71k | goto fail; |
389 | 7.82k | dt.year = aValue; |
390 | 7.82k | yearSign = aSign; |
391 | 7.82k | c = c_read8(aString++); |
392 | 7.82k | if (('0' <= c) && (c <= '9')) { |
393 | 6.02k | dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1; |
394 | 6.02k | if (c == '-') { |
395 | 4.83k | c = c_read8(aString++); |
396 | 4.83k | if (('0' <= c) && (c <= '9')) |
397 | 4.27k | dt.date = fx_Date_parse_number(&c, &aString, &overflow); |
398 | 565 | else |
399 | 565 | dt.date = 1; |
400 | 4.83k | } |
401 | 6.02k | } |
402 | 1.79k | else |
403 | 1.79k | dt.month = 0; |
404 | 7.82k | } |
405 | 20.6k | else { |
406 | 20.6k | if ((aDelta != 0) && (aDelta != -1)) |
407 | 1.75k | goto fail; |
408 | 18.9k | if (c == ':') { |
409 | 3.91k | aDelta = 60 * aValue; |
410 | 3.91k | c = c_read8(aString++); |
411 | 3.91k | if (('0' <= c) && (c <= '9')) { |
412 | 1.97k | aDelta += fx_Date_parse_number(&c, &aString, &overflow); |
413 | 1.97k | } |
414 | 3.91k | } |
415 | 15.0k | else { |
416 | 15.0k | if (aValue < 24) |
417 | 7.47k | aDelta = aValue * 60; |
418 | 7.52k | else |
419 | 7.52k | aDelta = (aValue % 100) + ((aValue / 100) * 60); |
420 | 15.0k | } |
421 | 18.9k | aDelta *= aSign; |
422 | 18.9k | } |
423 | 30.2k | } |
424 | 943 | else |
425 | 943 | goto fail; |
426 | 31.1k | } |
427 | 1.43M | else if (('0' <= c) && (c <= '9')) { |
428 | 369k | aValue = fx_Date_parse_number(&c, &aString, &overflow); |
429 | 369k | if (c == ':') { |
430 | 54.7k | if (dt.hours >= 0) |
431 | 603 | goto fail; |
432 | 54.1k | dt.hours = aValue; |
433 | 54.1k | c = c_read8(aString++); |
434 | 54.1k | if (('0' <= c) && (c <= '9')) { |
435 | 41.8k | dt.minutes = fx_Date_parse_number(&c, &aString, &overflow); |
436 | 41.8k | if (c == ':') { |
437 | 36.8k | c = c_read8(aString++); |
438 | 36.8k | if (('0' <= c) && (c <= '9')) { |
439 | 34.0k | dt.seconds = fx_Date_parse_number(&c, &aString, &overflow); |
440 | 34.0k | if (c == '.') { |
441 | 4.93k | c = c_read8(aString++); |
442 | 4.93k | if (('0' <= c) && (c <= '9')) { |
443 | 2.96k | dt.milliseconds = fx_Date_parse_fraction(&c, &aString); |
444 | 2.96k | } |
445 | 4.93k | } |
446 | 34.0k | } |
447 | 2.84k | else |
448 | 2.84k | dt.seconds = 0; |
449 | 36.8k | } |
450 | 41.8k | } |
451 | 12.3k | else |
452 | 12.3k | dt.seconds = 0; |
453 | 54.1k | } |
454 | 314k | else if (c == '/') { |
455 | 4.65k | if (dt.year >= 0) |
456 | 723 | goto fail; |
457 | 3.93k | dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue; |
458 | 3.93k | c = c_read8(aString++); |
459 | 3.93k | if (('0' <= c) && (c <= '9')) { |
460 | 3.32k | dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1; |
461 | 3.32k | if (c == '/') { |
462 | 1.72k | c = c_read8(aString++); |
463 | 1.72k | if (('0' <= c) && (c <= '9')) { |
464 | 1.26k | dt.date = fx_Date_parse_number(&c, &aString, &overflow); |
465 | 1.26k | } |
466 | 460 | else |
467 | 460 | dt.date = 1; |
468 | 1.72k | } |
469 | 3.32k | } |
470 | 608 | else |
471 | 608 | dt.month = 0; |
472 | 3.93k | } |
473 | 309k | else if (c == '-') { |
474 | 266k | if (dt.year >= 0) |
475 | 1.91k | goto fail; |
476 | 264k | dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue; |
477 | 264k | c = c_read8(aString++); |
478 | 264k | if (('0' <= c) && (c <= '9')) { |
479 | 263k | dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1; |
480 | 263k | if (c == '-') { |
481 | 886 | c = c_read8(aString++); |
482 | 886 | if (('0' <= c) && (c <= '9')) |
483 | 503 | dt.date = fx_Date_parse_number(&c, &aString, &overflow); |
484 | 383 | else |
485 | 383 | dt.date = 1; |
486 | 886 | } |
487 | 263k | } |
488 | 905 | else |
489 | 905 | dt.month = 0; |
490 | 264k | } |
491 | 43.3k | else { |
492 | 43.3k | if (aValue < 70) { |
493 | 26.5k | if (dt.date < 0) |
494 | 23.6k | dt.date = aValue; |
495 | 2.95k | else |
496 | 2.95k | goto fail; |
497 | 26.5k | } |
498 | 16.7k | else { |
499 | 16.7k | if (dt.year < 0) |
500 | 15.0k | dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue; |
501 | 1.71k | else |
502 | 1.71k | goto fail; |
503 | 16.7k | } |
504 | 43.3k | } |
505 | 369k | } |
506 | 1.06M | else if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'))) { |
507 | 798k | txSize cmpLength; |
508 | 798k | p = buffer; |
509 | 798k | q = p + sizeof(buffer) - 1; |
510 | 3.81M | do { |
511 | 3.81M | if (p == q) goto fail; |
512 | 3.54M | *p++ = (c >= 'a') ? c : (c + ('a' - 'A')); |
513 | 3.54M | c = c_read8(aString++); |
514 | 3.54M | } while ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'))); |
515 | 527k | *p = 0; |
516 | 527k | aLength = mxPtrDiff(p - (txString)buffer); |
517 | 527k | cmpLength = (aLength >= 3) ? aLength : 3; |
518 | 527k | if (c_strcmp("am", buffer) == 0) { |
519 | 7.15k | if ((dt.hours < 0) || (12 < dt.hours)) |
520 | 3.33k | goto fail; |
521 | 3.82k | if (dt.hours == 12) |
522 | 1.52k | dt.hours = 0; |
523 | 3.82k | continue; |
524 | 7.15k | } |
525 | 520k | if (c_strcmp("pm", buffer) == 0) { |
526 | 5.76k | if ((dt.hours < 0) || (12 < dt.hours)) |
527 | 2.56k | goto fail; |
528 | 3.20k | if (dt.hours != 12) |
529 | 1.46k | dt.hours += 12; |
530 | 3.20k | continue; |
531 | 5.76k | } |
532 | 4.08M | for (i = 0; i < mxDayCount; i++) |
533 | 3.58M | if (c_strncmp(gxDays[i], buffer, cmpLength) == 0) |
534 | 7.55k | break; |
535 | 514k | if (i < mxDayCount) |
536 | 7.55k | continue; |
537 | 6.53M | for (i = 0; i < mxMonthCount; i++) |
538 | 6.03M | if (c_strncmp(gxMonths[i], buffer, cmpLength) == 0) |
539 | 7.91k | break; |
540 | 507k | if (i < mxMonthCount) { |
541 | 7.91k | if (dt.month < 0) { |
542 | 7.56k | dt.month = i; |
543 | 7.56k | continue; |
544 | 7.56k | } |
545 | 348 | else |
546 | 348 | goto fail; |
547 | 7.91k | } |
548 | 5.83M | for (i = 0; i < mxZoneCount; i++) |
549 | 5.44M | if (c_strcmp(gxZones[i], buffer) == 0) |
550 | 111k | break; |
551 | 499k | if (i < mxZoneCount) { |
552 | 111k | if (aDelta == -1) { |
553 | 107k | aDelta = gxDeltas[i] * 60; |
554 | 107k | continue; |
555 | 107k | } |
556 | 4.57k | else |
557 | 4.57k | goto fail; |
558 | 111k | } |
559 | 387k | if (c_strcmp("t", buffer) == 0) { |
560 | 25.9k | if (dt.year < 0) |
561 | 490 | goto fail; |
562 | 25.4k | continue; |
563 | 25.9k | } |
564 | 361k | if (c_strcmp("z", buffer) == 0) { |
565 | 10.1k | if (dt.hours < 0) |
566 | 1.62k | goto fail; |
567 | 8.55k | aDelta = 0; |
568 | 8.55k | continue; |
569 | 10.1k | } |
570 | 351k | goto fail; |
571 | 361k | } |
572 | 265k | else |
573 | 265k | goto fail; |
574 | 8.47M | } |
575 | 13.5k | if (overflow) |
576 | 1.16k | goto fail; |
577 | 12.4k | if (dt.year < 0) |
578 | 4.85k | goto fail; |
579 | 7.57k | if ((yearSign < 0) && (dt.year == 0)) |
580 | 588 | goto fail; |
581 | 6.98k | if (dt.month < 0) |
582 | 3.46k | dt.month = 0; |
583 | 6.98k | if (dt.date < 0) |
584 | 3.91k | dt.date = 1; |
585 | 6.98k | if ((aDelta < 0) && (dt.hours < 0) && (dt.minutes < 0) && (dt.seconds < 0) && (dt.milliseconds < 0)) |
586 | 1.02k | aDelta = 0; |
587 | 6.98k | if (dt.hours < 0) |
588 | 1.15k | dt.hours = 0; |
589 | 6.98k | if (dt.minutes < 0) |
590 | 4.20k | dt.minutes = 0; |
591 | 6.98k | if (dt.seconds < 0) |
592 | 3.78k | dt.seconds = 0; |
593 | 6.98k | if (dt.milliseconds < 0) |
594 | 6.96k | dt.milliseconds = 0; |
595 | 6.98k | dt.year *= yearSign; |
596 | 6.98k | mxResult->value.number = fxDateMerge(&dt, (aDelta != -1) ? 1 : 0); |
597 | 6.98k | if (aDelta != -1) |
598 | 3.57k | mxResult->value.number -= (txNumber)aDelta * 60000.0; |
599 | 6.98k | mxResult->kind = XS_NUMBER_KIND; |
600 | 6.98k | return; |
601 | 923k | fail: |
602 | 923k | mxResult->value.number = C_NAN; |
603 | 923k | mxResult->kind = XS_NUMBER_KIND; |
604 | | //mxSyntaxError("invalid parameter"); |
605 | 923k | } |
606 | | |
607 | | void fx_Date_UTC(txMachine* the) |
608 | 119k | { |
609 | 119k | txInteger c = mxArgc; |
610 | 119k | txDateTime dt; |
611 | 119k | dt.year = (c > 0) ? fxDateFullYear(the, mxArgv(0)) : C_NAN; |
612 | 119k | dt.month = (c > 1) ? fxToNumber(the, mxArgv(1)) : 0; |
613 | 119k | dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1; |
614 | 119k | dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0; |
615 | 119k | dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0; |
616 | 119k | dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0; |
617 | 119k | dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0; |
618 | 119k | mxResult->value.number = fxDateMerge(&dt, 1); |
619 | 119k | mxResult->kind = XS_NUMBER_KIND; |
620 | 119k | } |
621 | | |
622 | | txBoolean fx_Date_prototype_get_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot) |
623 | 208k | { |
624 | 208k | txNumber number; |
625 | | #if mxAliasInstance |
626 | | txSlot* instance = mxThis->value.reference; |
627 | | if (instance->ID) { |
628 | | txSlot* alias = the->aliasArray[instance->ID]; |
629 | | if (alias) { |
630 | | instance = alias; |
631 | | slot = instance->next; |
632 | | } |
633 | | } |
634 | | #endif |
635 | 208k | number = slot->value.number; |
636 | 208k | if (c_isnan(number)) { |
637 | 175k | mxResult->value.number = C_NAN; |
638 | 175k | mxResult->kind = XS_NUMBER_KIND; |
639 | 175k | dt->value = C_NAN; |
640 | 175k | return 0; |
641 | 175k | } |
642 | 32.7k | fxDateSplit(slot->value.number, utc, dt); |
643 | 32.7k | return 1; |
644 | 208k | } |
645 | | |
646 | | void fx_Date_prototype_set_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot) |
647 | 412 | { |
648 | 412 | txNumber number = dt->value; |
649 | | #if mxAliasInstance |
650 | | txSlot* instance = mxThis->value.reference; |
651 | | if (instance->ID) { |
652 | | txSlot* alias = the->aliasArray[instance->ID]; |
653 | | if (alias) |
654 | | instance = alias; |
655 | | else |
656 | | instance = fxAliasInstance(the, instance); |
657 | | slot = instance->next; |
658 | | } |
659 | | #endif |
660 | 412 | if (c_isnan(number)) |
661 | 85 | return; |
662 | 327 | if (slot->flag & XS_DONT_SET_FLAG) |
663 | 0 | mxTypeError("this: read-only Date instance"); |
664 | 327 | mxResult->value.number = slot->value.number = fxDateMerge(dt, utc); |
665 | 327 | mxResult->kind = XS_NUMBER_KIND; |
666 | 327 | } |
667 | | |
668 | | void fx_Date_prototype_getMilliseconds(txMachine* the) |
669 | 79 | { |
670 | 79 | txDateTime dt; |
671 | 79 | txSlot* slot = fxDateCheck(the); |
672 | 79 | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
673 | 23 | mxResult->value.integer = (txInteger)dt.milliseconds; |
674 | 23 | mxResult->kind = XS_INTEGER_KIND; |
675 | 23 | } |
676 | 79 | } |
677 | | |
678 | | void fx_Date_prototype_getSeconds(txMachine* the) |
679 | 37 | { |
680 | 37 | txDateTime dt; |
681 | 37 | txSlot* slot = fxDateCheck(the); |
682 | 37 | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
683 | 18 | mxResult->value.integer = (txInteger)dt.seconds; |
684 | 18 | mxResult->kind = XS_INTEGER_KIND; |
685 | 18 | } |
686 | 37 | } |
687 | | |
688 | | void fx_Date_prototype_getMinutes(txMachine* the) |
689 | 39 | { |
690 | 39 | txDateTime dt; |
691 | 39 | txSlot* slot = fxDateCheck(the); |
692 | 39 | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
693 | 18 | mxResult->value.integer = (txInteger)dt.minutes; |
694 | 18 | mxResult->kind = XS_INTEGER_KIND; |
695 | 18 | } |
696 | 39 | } |
697 | | |
698 | | void fx_Date_prototype_getHours(txMachine* the) |
699 | 42 | { |
700 | 42 | txDateTime dt; |
701 | 42 | txSlot* slot = fxDateCheck(the); |
702 | 42 | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
703 | 19 | mxResult->value.integer = (txInteger)dt.hours; |
704 | 19 | mxResult->kind = XS_INTEGER_KIND; |
705 | 19 | } |
706 | 42 | } |
707 | | |
708 | | void fx_Date_prototype_getDay(txMachine* the) |
709 | 158k | { |
710 | 158k | txDateTime dt; |
711 | 158k | txSlot* slot = fxDateCheck(the); |
712 | 158k | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
713 | 20 | mxResult->value.integer = dt.day; |
714 | 20 | mxResult->kind = XS_INTEGER_KIND; |
715 | 20 | } |
716 | 158k | } |
717 | | |
718 | | void fx_Date_prototype_getDate(txMachine* the) |
719 | 80 | { |
720 | 80 | txDateTime dt; |
721 | 80 | txSlot* slot = fxDateCheck(the); |
722 | 80 | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
723 | 21 | mxResult->value.integer = (txInteger)dt.date; |
724 | 21 | mxResult->kind = XS_INTEGER_KIND; |
725 | 21 | } |
726 | 80 | } |
727 | | |
728 | | void fx_Date_prototype_getMonth(txMachine* the) |
729 | 33 | { |
730 | 33 | txDateTime dt; |
731 | 33 | txSlot* slot = fxDateCheck(the); |
732 | 33 | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
733 | 17 | mxResult->value.integer = (txInteger)dt.month; |
734 | 17 | mxResult->kind = XS_INTEGER_KIND; |
735 | 17 | } |
736 | 33 | } |
737 | | |
738 | | void fx_Date_prototype_getYear(txMachine* the) |
739 | 2 | { |
740 | 2 | txDateTime dt; |
741 | 2 | txSlot* slot = fxDateCheck(the); |
742 | 2 | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
743 | 1 | mxResult->value.integer = (txInteger)dt.year - 1900; |
744 | 1 | mxResult->kind = XS_INTEGER_KIND; |
745 | 1 | } |
746 | 2 | } |
747 | | |
748 | | void fx_Date_prototype_getFullYear(txMachine* the) |
749 | 37 | { |
750 | 37 | txDateTime dt; |
751 | 37 | txSlot* slot = fxDateCheck(the); |
752 | 37 | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
753 | 15 | mxResult->value.integer = (txInteger)dt.year; |
754 | 15 | mxResult->kind = XS_INTEGER_KIND; |
755 | 15 | } |
756 | 37 | } |
757 | | |
758 | | void fx_Date_prototype_getUTCMilliseconds(txMachine* the) |
759 | 78 | { |
760 | 78 | txDateTime dt; |
761 | 78 | txSlot* slot = fxDateCheck(the); |
762 | 78 | if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) { |
763 | 12 | mxResult->value.integer = (txInteger)dt.milliseconds; |
764 | 12 | mxResult->kind = XS_INTEGER_KIND; |
765 | 12 | } |
766 | 78 | } |
767 | | |
768 | | void fx_Date_prototype_getUTCSeconds(txMachine* the) |
769 | 864 | { |
770 | 864 | txDateTime dt; |
771 | 864 | txSlot* slot = fxDateCheck(the); |
772 | 864 | if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) { |
773 | 20 | mxResult->value.integer = (txInteger)dt.seconds; |
774 | 20 | mxResult->kind = XS_INTEGER_KIND; |
775 | 20 | } |
776 | 864 | } |
777 | | |
778 | | void fx_Date_prototype_getUTCMinutes(txMachine* the) |
779 | 47 | { |
780 | 47 | txDateTime dt; |
781 | 47 | txSlot* slot = fxDateCheck(the); |
782 | 47 | if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) { |
783 | 18 | mxResult->value.integer = (txInteger)dt.minutes; |
784 | 18 | mxResult->kind = XS_INTEGER_KIND; |
785 | 18 | } |
786 | 47 | } |
787 | | |
788 | | void fx_Date_prototype_getUTCHours(txMachine* the) |
789 | 41 | { |
790 | 41 | txDateTime dt; |
791 | 41 | txSlot* slot = fxDateCheck(the); |
792 | 41 | if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) { |
793 | 18 | mxResult->value.integer = (txInteger)dt.hours; |
794 | 18 | mxResult->kind = XS_INTEGER_KIND; |
795 | 18 | } |
796 | 41 | } |
797 | | |
798 | | void fx_Date_prototype_getUTCDay(txMachine* the) |
799 | 58 | { |
800 | 58 | txDateTime dt; |
801 | 58 | txSlot* slot = fxDateCheck(the); |
802 | 58 | if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) { |
803 | 27 | mxResult->value.integer = dt.day; |
804 | 27 | mxResult->kind = XS_INTEGER_KIND; |
805 | 27 | } |
806 | 58 | } |
807 | | |
808 | | void fx_Date_prototype_getUTCDate(txMachine* the) |
809 | 41 | { |
810 | 41 | txDateTime dt; |
811 | 41 | txSlot* slot = fxDateCheck(the); |
812 | 41 | if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) { |
813 | 19 | mxResult->value.integer = (txInteger)dt.date; |
814 | 19 | mxResult->kind = XS_INTEGER_KIND; |
815 | 19 | } |
816 | 41 | } |
817 | | |
818 | | void fx_Date_prototype_getUTCMonth(txMachine* the) |
819 | 45 | { |
820 | 45 | txDateTime dt; |
821 | 45 | txSlot* slot = fxDateCheck(the); |
822 | 45 | if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) { |
823 | 21 | mxResult->value.integer = (txInteger)dt.month; |
824 | 21 | mxResult->kind = XS_INTEGER_KIND; |
825 | 21 | } |
826 | 45 | } |
827 | | |
828 | | void fx_Date_prototype_getUTCFullYear(txMachine* the) |
829 | 49 | { |
830 | 49 | txDateTime dt; |
831 | 49 | txSlot* slot = fxDateCheck(the); |
832 | 49 | if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) { |
833 | 12 | mxResult->value.integer = (txInteger)dt.year; |
834 | 12 | mxResult->kind = XS_INTEGER_KIND; |
835 | 12 | } |
836 | 49 | } |
837 | | |
838 | | void fx_Date_prototype_getTimezoneOffset(txMachine* the) |
839 | 55 | { |
840 | 55 | txDateTime dt; |
841 | 55 | txSlot* slot = fxDateCheck(the); |
842 | 55 | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
843 | 15 | mxResult->value.integer = 0 - dt.offset; |
844 | 15 | mxResult->kind = XS_INTEGER_KIND; |
845 | 15 | } |
846 | 55 | } |
847 | | |
848 | | void fx_Date_prototype_setMilliseconds(txMachine* the) |
849 | 46 | { |
850 | 46 | txInteger c = mxArgc; |
851 | 46 | txDateTime dt; |
852 | 46 | txSlot* slot = fxDateCheck(the); |
853 | 46 | fx_Date_prototype_get_aux(the, &dt, 0, slot); |
854 | 46 | dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
855 | 46 | fx_Date_prototype_set_aux(the, &dt, 0, slot); |
856 | 46 | } |
857 | | |
858 | | void fx_Date_prototype_setSeconds(txMachine* the) |
859 | 66 | { |
860 | 66 | txInteger c = mxArgc; |
861 | 66 | txDateTime dt; |
862 | 66 | txSlot* slot = fxDateCheck(the); |
863 | 66 | fx_Date_prototype_get_aux(the, &dt, 0, slot); |
864 | 66 | dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
865 | 66 | if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1)); |
866 | 66 | fx_Date_prototype_set_aux(the, &dt, 0, slot); |
867 | 66 | } |
868 | | |
869 | | void fx_Date_prototype_setMinutes(txMachine* the) |
870 | 1.90k | { |
871 | 1.90k | txInteger c = mxArgc; |
872 | 1.90k | txDateTime dt; |
873 | 1.90k | txSlot* slot = fxDateCheck(the); |
874 | 1.90k | fx_Date_prototype_get_aux(the, &dt, 0, slot); |
875 | 1.90k | dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
876 | 1.90k | if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1)); |
877 | 1.90k | if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2)); |
878 | 1.90k | fx_Date_prototype_set_aux(the, &dt, 0, slot); |
879 | 1.90k | } |
880 | | |
881 | | void fx_Date_prototype_setHours(txMachine* the) |
882 | 1.91k | { |
883 | 1.91k | txInteger c = mxArgc; |
884 | 1.91k | txDateTime dt; |
885 | 1.91k | txSlot* slot = fxDateCheck(the); |
886 | 1.91k | fx_Date_prototype_get_aux(the, &dt, 0, slot); |
887 | 1.91k | dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
888 | 1.91k | if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1)); |
889 | 1.91k | if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2)); |
890 | 1.91k | if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3)); |
891 | 1.91k | fx_Date_prototype_set_aux(the, &dt, 0, slot); |
892 | 1.91k | } |
893 | | |
894 | | void fx_Date_prototype_setDate(txMachine* the) |
895 | 53 | { |
896 | 53 | txInteger c = mxArgc; |
897 | 53 | txDateTime dt; |
898 | 53 | txSlot* slot = fxDateCheck(the); |
899 | 53 | fx_Date_prototype_get_aux(the, &dt, 0, slot); |
900 | 53 | dt.date = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
901 | 53 | fx_Date_prototype_set_aux(the, &dt, 0, slot); |
902 | 53 | } |
903 | | |
904 | | void fx_Date_prototype_setMonth(txMachine* the) |
905 | 61 | { |
906 | 61 | txInteger c = mxArgc; |
907 | 61 | txDateTime dt; |
908 | 61 | txSlot* slot = fxDateCheck(the); |
909 | 61 | fx_Date_prototype_get_aux(the, &dt, 0, slot); |
910 | 61 | dt.month = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
911 | 61 | if (c > 1) dt.date = fxToNumber(the, mxArgv(1)); |
912 | 61 | fx_Date_prototype_set_aux(the, &dt, 0, slot); |
913 | 61 | } |
914 | | |
915 | | void fx_Date_prototype_setYear(txMachine* the) |
916 | 0 | { |
917 | 0 | txInteger c = mxArgc; |
918 | 0 | txDateTime dt; |
919 | 0 | txSlot* slot = fxDateCheck(the); |
920 | 0 | if (c_isnan(slot->value.number)) { |
921 | 0 | slot->value.number = 0; |
922 | 0 | fx_Date_prototype_get_aux(the, &dt, 1, slot); |
923 | 0 | } |
924 | 0 | else |
925 | 0 | fx_Date_prototype_get_aux(the, &dt, 0, slot); |
926 | 0 | dt.year = (mxArgc > 0) ? fxDateFullYear(the, mxArgv(0)) : C_NAN; |
927 | 0 | if (c > 1) dt.month = fxToNumber(the, mxArgv(1)); |
928 | 0 | if (c > 2) dt.date = fxToNumber(the, mxArgv(2)); |
929 | 0 | fx_Date_prototype_set_aux(the, &dt, 0, slot); |
930 | 0 | } |
931 | | |
932 | | void fx_Date_prototype_setFullYear(txMachine* the) |
933 | 1.90k | { |
934 | 1.90k | txInteger c = mxArgc; |
935 | 1.90k | txDateTime dt; |
936 | 1.90k | txSlot* slot = fxDateCheck(the); |
937 | 1.90k | if (c_isnan(slot->value.number)) { |
938 | 9 | slot->value.number = 0; |
939 | 9 | fx_Date_prototype_get_aux(the, &dt, 1, slot); |
940 | 9 | } |
941 | 1.89k | else |
942 | 1.89k | fx_Date_prototype_get_aux(the, &dt, 0, slot); |
943 | 1.90k | dt.year = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
944 | 1.90k | if (c > 1) dt.month = fxToNumber(the, mxArgv(1)); |
945 | 1.90k | if (c > 2) dt.date = fxToNumber(the, mxArgv(2)); |
946 | 1.90k | fx_Date_prototype_set_aux(the, &dt, 0, slot); |
947 | 1.90k | } |
948 | | |
949 | | void fx_Date_prototype_setTime(txMachine* the) |
950 | 1.96k | { |
951 | 1.96k | txSlot* slot = fxDateCheck(the); |
952 | 1.96k | if (slot->flag & XS_DONT_SET_FLAG) |
953 | 0 | mxTypeError("this: read-only Date instance"); |
954 | 1.96k | if (mxArgc < 1) |
955 | 2 | slot->value.number = C_NAN; |
956 | 1.96k | else { |
957 | 1.96k | txNumber number = fxToNumber(the, mxArgv(0)); |
958 | 1.96k | int fpclass = c_fpclassify(number); |
959 | 1.96k | if (fpclass != C_FP_NAN) { |
960 | 1.92k | if (c_fabs(number) > 8.64e15) |
961 | 1 | number = C_NAN; |
962 | 1.92k | else |
963 | 1.92k | number = c_trunc(number); |
964 | 1.92k | } |
965 | 1.96k | slot->value.number = number; |
966 | 1.96k | } |
967 | 1.96k | mxResult->value.number = slot->value.number; |
968 | 1.96k | mxResult->kind = XS_NUMBER_KIND; |
969 | 1.96k | } |
970 | | |
971 | | void fx_Date_prototype_setUTCMilliseconds(txMachine* the) |
972 | 8 | { |
973 | 8 | txInteger c = mxArgc; |
974 | 8 | txDateTime dt; |
975 | 8 | txSlot* slot = fxDateCheck(the); |
976 | 8 | fx_Date_prototype_get_aux(the, &dt, 1, slot); |
977 | 8 | dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
978 | 8 | fx_Date_prototype_set_aux(the, &dt, 1, slot); |
979 | 8 | } |
980 | | |
981 | | void fx_Date_prototype_setUTCSeconds(txMachine* the) |
982 | 12 | { |
983 | 12 | txInteger c = mxArgc; |
984 | 12 | txDateTime dt; |
985 | 12 | txSlot* slot = fxDateCheck(the); |
986 | 12 | fx_Date_prototype_get_aux(the, &dt, 1, slot); |
987 | 12 | dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
988 | 12 | if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1)); |
989 | 12 | fx_Date_prototype_set_aux(the, &dt, 1, slot); |
990 | 12 | } |
991 | | |
992 | | void fx_Date_prototype_setUTCMinutes(txMachine* the) |
993 | 39 | { |
994 | 39 | txInteger c = mxArgc; |
995 | 39 | txDateTime dt; |
996 | 39 | txSlot* slot = fxDateCheck(the); |
997 | 39 | fx_Date_prototype_get_aux(the, &dt, 1, slot); |
998 | 39 | dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
999 | 39 | if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1)); |
1000 | 39 | if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2)); |
1001 | 39 | fx_Date_prototype_set_aux(the, &dt, 1, slot); |
1002 | 39 | } |
1003 | | |
1004 | | void fx_Date_prototype_setUTCHours(txMachine* the) |
1005 | 32 | { |
1006 | 32 | txInteger c = mxArgc; |
1007 | 32 | txDateTime dt; |
1008 | 32 | txSlot* slot = fxDateCheck(the); |
1009 | 32 | fx_Date_prototype_get_aux(the, &dt, 1, slot); |
1010 | 32 | dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
1011 | 32 | if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1)); |
1012 | 32 | if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2)); |
1013 | 32 | if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3)); |
1014 | 32 | fx_Date_prototype_set_aux(the, &dt, 1, slot); |
1015 | 32 | } |
1016 | | |
1017 | | void fx_Date_prototype_setUTCDate(txMachine* the) |
1018 | 1.84k | { |
1019 | 1.84k | txInteger c = mxArgc; |
1020 | 1.84k | txDateTime dt; |
1021 | 1.84k | txSlot* slot = fxDateCheck(the); |
1022 | 1.84k | fx_Date_prototype_get_aux(the, &dt, 1, slot); |
1023 | 1.84k | dt.date = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
1024 | 1.84k | fx_Date_prototype_set_aux(the, &dt, 1, slot); |
1025 | 1.84k | } |
1026 | | |
1027 | | void fx_Date_prototype_setUTCMonth(txMachine* the) |
1028 | 1.86k | { |
1029 | 1.86k | txInteger c = mxArgc; |
1030 | 1.86k | txDateTime dt; |
1031 | 1.86k | txSlot* slot = fxDateCheck(the); |
1032 | 1.86k | fx_Date_prototype_get_aux(the, &dt, 1, slot); |
1033 | 1.86k | dt.month = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
1034 | 1.86k | if (c > 1) dt.date = fxToNumber(the, mxArgv(1)); |
1035 | 1.86k | fx_Date_prototype_set_aux(the, &dt, 1, slot); |
1036 | 1.86k | } |
1037 | | |
1038 | | void fx_Date_prototype_setUTCFullYear(txMachine* the) |
1039 | 7 | { |
1040 | 7 | txInteger c = mxArgc; |
1041 | 7 | txDateTime dt; |
1042 | 7 | txSlot* slot = fxDateCheck(the); |
1043 | 7 | if (c_isnan(slot->value.number)) slot->value.number = 0; |
1044 | 7 | fx_Date_prototype_get_aux(the, &dt, 1, slot); |
1045 | 7 | dt.year = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN; |
1046 | 7 | if (c > 1) dt.month = fxToNumber(the, mxArgv(1)); |
1047 | 7 | if (c > 2) dt.date = fxToNumber(the, mxArgv(2)); |
1048 | 7 | fx_Date_prototype_set_aux(the, &dt, 1, slot); |
1049 | 7 | } |
1050 | | |
1051 | | void fx_Date_prototype_toDateString(txMachine* the) |
1052 | 5.95k | { |
1053 | 5.95k | char buffer[256]; |
1054 | 5.95k | txDateTime dt; |
1055 | 5.95k | txSlot* slot = fxDateCheck(the); |
1056 | 5.95k | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
1057 | 2.70k | txString p = buffer; |
1058 | 2.70k | p = fxDatePrintDay(p, dt.day); |
1059 | 2.70k | *p++ = ' '; |
1060 | 2.70k | p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date); |
1061 | 2.70k | *p = 0; |
1062 | 2.70k | } |
1063 | 3.25k | else |
1064 | 3.25k | c_strcpy(buffer, "Invalid Date"); |
1065 | 5.95k | fxCopyStringC(the, mxResult, buffer); |
1066 | 5.95k | } |
1067 | | |
1068 | | void fx_Date_prototype_toISOString(txMachine* the) |
1069 | 22 | { |
1070 | 22 | char buffer[256]; |
1071 | 22 | txDateTime dt; |
1072 | 22 | txSlot* slot = fxDateCheck(the); |
1073 | 22 | if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) { |
1074 | 16 | txString p = buffer; |
1075 | 16 | p = fxDatePrintYear(p, (txInteger)dt.year); |
1076 | 16 | *p++ = '-'; |
1077 | 16 | p = fxDatePrint2Digits(p, (txInteger)dt.month + 1); |
1078 | 16 | *p++ = '-'; |
1079 | 16 | p = fxDatePrint2Digits(p, (txInteger)dt.date); |
1080 | 16 | *p++ = 'T'; |
1081 | 16 | p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds); |
1082 | 16 | *p++ = '.'; |
1083 | 16 | p = fxDatePrint3Digits(p, (txInteger)dt.milliseconds); |
1084 | 16 | *p++ = 'Z'; |
1085 | 16 | *p = 0; |
1086 | 16 | } |
1087 | 6 | else |
1088 | 6 | mxRangeError("Invalid Date"); |
1089 | 16 | fxCopyStringC(the, mxResult, buffer); |
1090 | 16 | } |
1091 | | |
1092 | | void fx_Date_prototype_toJSON(txMachine* the) |
1093 | 13 | { |
1094 | 13 | fxToInstance(the, mxThis); |
1095 | 13 | mxPushSlot(mxThis); |
1096 | 13 | fxToPrimitive(the, the->stack, XS_NUMBER_HINT); |
1097 | 13 | if ((the->stack->kind == XS_NUMBER_KIND) && !c_isfinite(the->stack->value.number)) { |
1098 | 3 | mxPop(); |
1099 | 3 | mxResult->kind = XS_NULL_KIND; |
1100 | 3 | } |
1101 | 10 | else { |
1102 | 10 | mxPop(); |
1103 | 10 | mxPushSlot(mxThis); |
1104 | 10 | mxDub(); |
1105 | 10 | mxGetID(mxID(_toISOString)); |
1106 | 10 | mxCall(); |
1107 | 10 | mxRunCount(0); |
1108 | 10 | mxPullSlot(mxResult); |
1109 | 10 | } |
1110 | 13 | } |
1111 | | |
1112 | | void fx_Date_prototype_toPrimitive(txMachine* the) |
1113 | 44.7k | { |
1114 | 44.7k | if (mxIsReference(mxThis)) { |
1115 | 44.7k | txInteger hint = XS_NO_HINT; |
1116 | 44.7k | txInteger ids[2], i; |
1117 | 44.7k | if (mxArgc > 0) { |
1118 | 44.6k | txSlot* slot = mxArgv(0); |
1119 | 44.6k | if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) { |
1120 | 44.6k | if (!c_strcmp(slot->value.string, "default")) |
1121 | 30.1k | hint = XS_STRING_HINT; |
1122 | 14.5k | else if (!c_strcmp(slot->value.string, "number")) |
1123 | 13.7k | hint = XS_NUMBER_HINT; |
1124 | 797 | else if (!c_strcmp(slot->value.string, "string")) |
1125 | 782 | hint = XS_STRING_HINT; |
1126 | 44.6k | } |
1127 | 44.6k | } |
1128 | 44.7k | if (hint == XS_STRING_HINT) { |
1129 | 30.9k | ids[0] = mxID(_toString); |
1130 | 30.9k | ids[1] = mxID(_valueOf); |
1131 | 30.9k | } |
1132 | 13.8k | else if (hint == XS_NUMBER_HINT) { |
1133 | 13.7k | ids[0] = mxID(_valueOf); |
1134 | 13.7k | ids[1] = mxID(_toString); |
1135 | 13.7k | } |
1136 | 36 | else |
1137 | 36 | mxTypeError("invalid hint"); |
1138 | 44.6k | for (i = 0; i < 2; i++) { |
1139 | 44.6k | mxPushSlot(mxThis); |
1140 | 44.6k | mxPushSlot(mxThis); |
1141 | 44.6k | mxGetID(ids[i]); |
1142 | 44.6k | if (fxIsCallable(the, the->stack)) { |
1143 | 44.6k | mxCall(); |
1144 | 44.6k | mxRunCount(0); |
1145 | 44.6k | if (mxIsReference(the->stack)) |
1146 | 1 | mxPop(); |
1147 | 44.6k | else { |
1148 | 44.6k | mxPullSlot(mxResult); |
1149 | 44.6k | return; |
1150 | 44.6k | } |
1151 | 44.6k | } |
1152 | 5 | else { |
1153 | 5 | mxPop(); |
1154 | 5 | mxPop(); |
1155 | 5 | } |
1156 | 44.6k | } |
1157 | 2 | if (hint == XS_STRING_HINT) |
1158 | 1 | mxTypeError("cannot coerce object to string"); |
1159 | 1 | else |
1160 | 1 | mxTypeError("cannot coerce object to number"); |
1161 | 2 | } |
1162 | 11 | else { |
1163 | 11 | mxTypeError("invalid this"); |
1164 | 11 | } |
1165 | 44.7k | } |
1166 | | |
1167 | | void fx_Date_prototype_toString(txMachine* the) |
1168 | 30.9k | { |
1169 | 30.9k | char buffer[256]; |
1170 | 30.9k | txDateTime dt; |
1171 | 30.9k | txSlot* slot = fxDateCheck(the); |
1172 | 30.9k | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
1173 | 20.0k | txString p = buffer; |
1174 | 20.0k | p = fxDatePrintDay(p, dt.day); |
1175 | 20.0k | *p++ = ' '; |
1176 | 20.0k | p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date); |
1177 | 20.0k | *p++ = ' '; |
1178 | 20.0k | p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds); |
1179 | 20.0k | *p++ = ' '; |
1180 | 20.0k | p = fxDatePrintTimezone(p, (txInteger)dt.offset); |
1181 | 20.0k | *p = 0; |
1182 | 20.0k | } |
1183 | 10.8k | else |
1184 | 10.8k | c_strcpy(buffer, "Invalid Date"); |
1185 | 30.9k | fxCopyStringC(the, mxResult, buffer); |
1186 | 30.9k | } |
1187 | | |
1188 | | void fx_Date_prototype_toTimeString(txMachine* the) |
1189 | 2 | { |
1190 | 2 | char buffer[256]; |
1191 | 2 | txDateTime dt; |
1192 | 2 | txSlot* slot = fxDateCheck(the); |
1193 | 2 | if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) { |
1194 | 1 | txString p = buffer; |
1195 | 1 | p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds); |
1196 | 1 | *p++ = ' '; |
1197 | 1 | p = fxDatePrintTimezone(p, (txInteger)dt.offset); |
1198 | 1 | *p = 0; |
1199 | 1 | } |
1200 | 1 | else |
1201 | 1 | c_strcpy(buffer, "Invalid Date"); |
1202 | 2 | fxCopyStringC(the, mxResult, buffer); |
1203 | 2 | } |
1204 | | |
1205 | | void fx_Date_prototype_toUTCString(txMachine* the) |
1206 | 2.21k | { |
1207 | 2.21k | char buffer[256]; |
1208 | 2.21k | txDateTime dt; |
1209 | 2.21k | txSlot* slot = fxDateCheck(the); |
1210 | 2.21k | if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) { |
1211 | 1.95k | txString p = buffer; |
1212 | 1.95k | p = fxDatePrintDay(p, dt.day); |
1213 | 1.95k | *p++ = ','; |
1214 | 1.95k | *p++ = ' '; |
1215 | 1.95k | p = fxDatePrintDateUTC(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date); |
1216 | 1.95k | *p++ = ' '; |
1217 | 1.95k | p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds); |
1218 | 1.95k | *p++ = ' '; |
1219 | 1.95k | *p++ = 'G'; |
1220 | 1.95k | *p++ = 'M'; |
1221 | 1.95k | *p++ = 'T'; |
1222 | 1.95k | *p = 0; |
1223 | 1.95k | } |
1224 | 255 | else |
1225 | 255 | c_strcpy(buffer, "Invalid Date"); |
1226 | 2.21k | fxCopyStringC(the, mxResult, buffer); |
1227 | 2.21k | } |
1228 | | |
1229 | | void fx_Date_prototype_valueOf(txMachine* the) |
1230 | 14.1k | { |
1231 | 14.1k | txSlot* slot = fxDateCheck(the); |
1232 | 14.1k | mxResult->kind = XS_NUMBER_KIND; |
1233 | 14.1k | mxResult->value = slot->value; |
1234 | 14.1k | } |
1235 | | |
1236 | | // Thanks Google V8 for the years offset |
1237 | | // Thanks Mozilla JS for the similar years |
1238 | | |
1239 | | static const txString gxDayNames[] ICACHE_XS6RO2_ATTR = { |
1240 | | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
1241 | | }; |
1242 | | static const txString gxMonthNames[] ICACHE_XS6RO2_ATTR = { |
1243 | | "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
1244 | | }; |
1245 | | static const txInteger gxCommonYearMonthsDays[12] ICACHE_XS6RO2_ATTR = { |
1246 | | 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 |
1247 | | }; |
1248 | | static const txInteger gxLeapYearMonthsDays[12] ICACHE_XS6RO2_ATTR = { |
1249 | | 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 |
1250 | | }; |
1251 | | static const txInteger gxSimilarCommonYears[7] ICACHE_XS6RO2_ATTR = { |
1252 | | 1978, 1973, 1974, 1975, 1981, 1971, 1977 |
1253 | | }; |
1254 | | static const txInteger gxSimilarLeapYears[7] ICACHE_XS6RO2_ATTR = { |
1255 | | 1984, 1996, 1980, 1992, 1976, 1988, 1972 |
1256 | | }; |
1257 | | |
1258 | 686k | #define mx1YearDays 365 |
1259 | 514k | #define mx4YearsDays ((4 * mx1YearDays) + 1) |
1260 | 343k | #define mx100YearsDays ((25 * mx4YearsDays) - 1) |
1261 | 171k | #define mx400YearsDays ((4 * mx100YearsDays) + 1) |
1262 | 346k | #define mxDayMilliseconds 86400000.0 |
1263 | | #define mxYearDays(YEAR) \ |
1264 | 355k | ((365 * (YEAR)) + ((YEAR) / 4) - ((YEAR) / 100) + ((YEAR) / 400) + 1) |
1265 | | #define mxIsLeapYear(YEAR) \ |
1266 | 134k | (((YEAR) % 4) ? 0 : ((YEAR) % 100) ? 1 : ((YEAR) % 400) ? 0 : 1) |
1267 | 306k | #define mxYearsOffset 400000 |
1268 | | |
1269 | | txSlot* fxDateCheck(txMachine* the) |
1270 | 225k | { |
1271 | 225k | txSlot* it = mxThis; |
1272 | 225k | if (it->kind == XS_REFERENCE_KIND) { |
1273 | 224k | txSlot* instance = it->value.reference; |
1274 | 224k | it = instance->next; |
1275 | 224k | if ((it) && (it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_DATE_KIND)) |
1276 | 224k | return it; |
1277 | 224k | } |
1278 | 225k | mxTypeError("this: not a Date instance"); |
1279 | 0 | return C_NULL; |
1280 | 225k | } |
1281 | | |
1282 | | txNumber fxDateClip(txNumber value) |
1283 | 589k | { |
1284 | 589k | if (!c_isfinite(value)) |
1285 | 159k | value = C_NAN; |
1286 | 430k | else if (c_fabs(value) > 8.64e15) |
1287 | 36.1k | value = C_NAN; |
1288 | 394k | else { |
1289 | 394k | value = c_trunc(value); |
1290 | 394k | if (value == 0) |
1291 | 4.36k | value = 0; |
1292 | 394k | } |
1293 | 589k | return value; |
1294 | 589k | } |
1295 | | |
1296 | | txNumber fxDateFullYear(txMachine* the, txSlot* slot) |
1297 | 151k | { |
1298 | 151k | txNumber result = fxToNumber(the, slot); |
1299 | 151k | if (c_isfinite(result)) { |
1300 | 149k | txInteger value = fxToInteger(the, slot); |
1301 | 149k | if ((0 <= value) && (value <= 99)) |
1302 | 21.8k | result = 1900 + value; |
1303 | 149k | } |
1304 | 151k | return result; |
1305 | 151k | } |
1306 | | |
1307 | | txNumber fxDateMerge(txDateTime* dt, txBoolean utc) |
1308 | 259k | { |
1309 | 259k | txNumber year, month; |
1310 | 259k | txInteger monthIndex; |
1311 | 259k | txBoolean leap; |
1312 | 259k | txNumber value; |
1313 | 259k | if ((!c_isfinite(dt->year)) |
1314 | 256k | || (!c_isfinite(dt->month)) |
1315 | 256k | || (!c_isfinite(dt->date)) |
1316 | 256k | || (!c_isfinite(dt->hours)) |
1317 | 255k | || (!c_isfinite(dt->minutes)) |
1318 | 255k | || (!c_isfinite(dt->seconds)) |
1319 | 172k | || (!c_isfinite(dt->milliseconds))) |
1320 | 87.7k | return C_NAN; |
1321 | 171k | year = c_trunc(dt->year); |
1322 | 171k | month = c_trunc(dt->month); |
1323 | 171k | year += c_floor(month / 12); |
1324 | 171k | monthIndex = (txInteger)c_fmod(month, 12.0); |
1325 | 171k | if (monthIndex < 0) |
1326 | 566 | monthIndex += 12; |
1327 | 171k | leap = (c_fmod(year, 4) == 0) && ((c_fmod(year, 100) != 0) || (c_fmod(year, 400) == 0)); |
1328 | 171k | year += mxYearsOffset - 1; |
1329 | 171k | value = (365 * year) + c_floor(year / 4) - c_floor(year / 100) + c_floor(year / 400) + 1; |
1330 | 171k | value -= (txNumber)mxYearDays(1970 + mxYearsOffset - 1); |
1331 | 171k | if (leap) |
1332 | 56.9k | value += gxLeapYearMonthsDays[monthIndex]; |
1333 | 114k | else |
1334 | 114k | value += gxCommonYearMonthsDays[monthIndex]; |
1335 | 171k | value += c_trunc(dt->date) - 1; |
1336 | 171k | value *= mxDayMilliseconds; |
1337 | 171k | value += c_trunc(dt->hours) * 60 * 60 * 1000; |
1338 | 171k | value += c_trunc(dt->minutes) * 60 * 1000; |
1339 | 171k | value += c_trunc(dt->seconds) * 1000; |
1340 | 171k | value += c_trunc(dt->milliseconds); |
1341 | 171k | if (!utc) { |
1342 | 32.5k | txNumber former = value; |
1343 | 32.5k | txInteger similar; |
1344 | 32.5k | c_tm tm; |
1345 | 32.5k | c_time_t time; |
1346 | 32.5k | fxDateSplit(value, 1, dt); |
1347 | 32.5k | similar = fxDateSimilarYear((txInteger)dt->year); |
1348 | 32.5k | c_memset(&tm, 0, sizeof(c_tm)); |
1349 | 32.5k | tm.tm_year = similar - 1900; |
1350 | 32.5k | tm.tm_mon = (txInteger)dt->month; |
1351 | 32.5k | tm.tm_mday = (txInteger)dt->date; |
1352 | 32.5k | tm.tm_hour = (txInteger)dt->hours; |
1353 | 32.5k | tm.tm_min = (txInteger)dt->minutes; |
1354 | 32.5k | tm.tm_sec = (txInteger)dt->seconds; |
1355 | 32.5k | tm.tm_isdst =-1; |
1356 | 32.5k | time = c_mktime(&tm); |
1357 | 32.5k | if (time == -1) |
1358 | 0 | value = NAN; |
1359 | 32.5k | else { |
1360 | 32.5k | value = (txNumber)time; |
1361 | 32.5k | value *= 1000; |
1362 | 32.5k | value += dt->milliseconds; |
1363 | 32.5k | if (similar != year) { |
1364 | 32.5k | dt->year = similar; |
1365 | 32.5k | value += former - fxDateMerge(dt, 1); |
1366 | 32.5k | } |
1367 | 32.5k | } |
1368 | 32.5k | } |
1369 | 171k | return fxDateClip(value); |
1370 | 259k | } |
1371 | | |
1372 | | txNumber fxDateNow() |
1373 | 257k | { |
1374 | 257k | c_timeval tv; |
1375 | 257k | c_gettimeofday(&tv, NULL); |
1376 | 257k | return fxDateClip(((txNumber)(tv.tv_sec) * 1000.0) + ((txNumber)(tv.tv_usec / 1000))); |
1377 | 257k | } |
1378 | | |
1379 | | txString fxDatePrint2Digits(txString p, txInteger value) |
1380 | 299k | { |
1381 | 299k | *p++ = '0' + value / 10; |
1382 | 299k | *p++ = '0' + value % 10; |
1383 | 299k | return p; |
1384 | 299k | } |
1385 | | |
1386 | | txString fxDatePrint3Digits(txString p, txInteger value) |
1387 | 45.2k | { |
1388 | 45.2k | *p++ = '0' + value / 100; |
1389 | 45.2k | return fxDatePrint2Digits(p, value % 100); |
1390 | 45.2k | } |
1391 | | |
1392 | | txString fxDatePrint4Digits(txString p, txInteger value) |
1393 | 45.2k | { |
1394 | 45.2k | *p++ = '0' + value / 1000; |
1395 | 45.2k | return fxDatePrint3Digits(p, value % 1000); |
1396 | 45.2k | } |
1397 | | |
1398 | | txString fxDatePrintDate(txString p, txInteger year, txInteger month, txInteger date) |
1399 | 43.2k | { |
1400 | 43.2k | c_strcpy(p, gxMonthNames[month]); |
1401 | 43.2k | p += 3; |
1402 | 43.2k | *p++ = ' '; |
1403 | 43.2k | p = fxDatePrint2Digits(p, date); |
1404 | 43.2k | *p++ = ' '; |
1405 | 43.2k | p = fxDatePrintYear(p, year); |
1406 | 43.2k | return p; |
1407 | 43.2k | } |
1408 | | |
1409 | | txString fxDatePrintDateUTC(txString p, txInteger year, txInteger month, txInteger date) |
1410 | 1.95k | { |
1411 | 1.95k | p = fxDatePrint2Digits(p, date); |
1412 | 1.95k | *p++ = ' '; |
1413 | 1.95k | c_strcpy(p, gxMonthNames[month]); |
1414 | 1.95k | p += 3; |
1415 | 1.95k | *p++ = ' '; |
1416 | 1.95k | p = fxDatePrintYear(p, year); |
1417 | 1.95k | return p; |
1418 | 1.95k | } |
1419 | | |
1420 | | txString fxDatePrintDay(txString p, txInteger day) |
1421 | 45.2k | { |
1422 | 45.2k | c_strcpy(p, gxDayNames[day]); |
1423 | 45.2k | p += 3; |
1424 | 45.2k | return p; |
1425 | 45.2k | } |
1426 | | |
1427 | | txString fxDatePrintTime(txString p, txInteger hours, txInteger minutes, txInteger seconds) |
1428 | 42.5k | { |
1429 | 42.5k | p = fxDatePrint2Digits(p, hours); |
1430 | 42.5k | *p++ = ':'; |
1431 | 42.5k | p = fxDatePrint2Digits(p, minutes); |
1432 | 42.5k | *p++ = ':'; |
1433 | 42.5k | p = fxDatePrint2Digits(p, seconds); |
1434 | 42.5k | return p; |
1435 | 42.5k | } |
1436 | | |
1437 | | txString fxDatePrintTimezone(txString p, txInteger offset) |
1438 | 40.5k | { |
1439 | 40.5k | *p++ = 'G'; |
1440 | 40.5k | *p++ = 'M'; |
1441 | 40.5k | *p++ = 'T'; |
1442 | 40.5k | if (offset < 0) { |
1443 | 0 | offset = 0 - offset; |
1444 | 0 | *p++ = '-'; |
1445 | 0 | } |
1446 | 40.5k | else |
1447 | 40.5k | *p++ = '+'; |
1448 | 40.5k | p = fxDatePrint2Digits(p, offset / 60); |
1449 | 40.5k | p = fxDatePrint2Digits(p, offset % 60); |
1450 | 40.5k | return p; |
1451 | 40.5k | } |
1452 | | |
1453 | | txString fxDatePrintYear(txString p, txInteger value) |
1454 | 45.2k | { |
1455 | 45.2k | if ((value < 0) || (9999 < value)) { |
1456 | 7.26k | if (value < 0) { |
1457 | 5.66k | *p++ = '-'; |
1458 | 5.66k | value = -value; |
1459 | 5.66k | } |
1460 | 1.59k | else |
1461 | 1.59k | *p++ = '+'; |
1462 | 7.26k | if (99999 < value) { |
1463 | 2.71k | *p++ = '0' + value / 100000; |
1464 | 2.71k | value %= 100000; |
1465 | 2.71k | } |
1466 | 7.26k | if (9999 < value) { |
1467 | 5.08k | *p++ = '0' + value / 10000; |
1468 | 5.08k | value %= 10000; |
1469 | 5.08k | } |
1470 | 7.26k | } |
1471 | 45.2k | return fxDatePrint4Digits(p, value); |
1472 | 45.2k | } |
1473 | | |
1474 | | txInteger fxDateSimilarYear(txInteger year) |
1475 | 81.7k | { |
1476 | 81.7k | txInteger leap, day; |
1477 | 81.7k | if ((1970 <= year) && (year < 2038)) |
1478 | 32.7k | return year; |
1479 | 49.0k | leap = mxIsLeapYear(year); |
1480 | 49.0k | year += mxYearsOffset - 1; |
1481 | 49.0k | day = mxYearDays(year) - mxYearDays(1970 + mxYearsOffset - 1); |
1482 | 49.0k | day = (day + 4) % 7; |
1483 | 49.0k | if (day < 0) |
1484 | 39.6k | day += 7; |
1485 | 49.0k | return (leap) ? gxSimilarLeapYears[day] : gxSimilarCommonYears[day]; |
1486 | 81.7k | } |
1487 | | |
1488 | | void fxDateSplit(txNumber value, txBoolean utc, txDateTime* dt) |
1489 | 85.8k | { |
1490 | 85.8k | txInteger date, time, year, leap, month; |
1491 | 85.8k | const txInteger* monthsDays; |
1492 | 85.8k | date = (txInteger)c_trunc(value / mxDayMilliseconds); |
1493 | 85.8k | time = (txInteger)c_fmod(value, mxDayMilliseconds); |
1494 | 85.8k | if (time < 0) { |
1495 | 3.28k | date--; |
1496 | 3.28k | time += (txInteger)mxDayMilliseconds; |
1497 | 3.28k | } |
1498 | 85.8k | dt->offset = 0; |
1499 | 85.8k | dt->day = (date + 4) % 7; |
1500 | 85.8k | if (dt->day < 0) |
1501 | 37.8k | dt->day += 7; |
1502 | 85.8k | dt->milliseconds = time % 1000; |
1503 | 85.8k | time /= 1000; |
1504 | 85.8k | dt->seconds = time % 60; |
1505 | 85.8k | time /= 60; |
1506 | 85.8k | dt->minutes = time % 60; |
1507 | 85.8k | time /= 60; |
1508 | 85.8k | dt->hours = time; |
1509 | 85.8k | date += mxYearDays(1970 + mxYearsOffset); |
1510 | 85.8k | year = 400 * (date / mx400YearsDays); |
1511 | 85.8k | date %= mx400YearsDays; |
1512 | 85.8k | date--; |
1513 | 85.8k | year += 100 * (date / mx100YearsDays); |
1514 | 85.8k | date %= mx100YearsDays; |
1515 | 85.8k | date++; |
1516 | 85.8k | year += 4 * (date / mx4YearsDays); |
1517 | 85.8k | date %= mx4YearsDays; |
1518 | 85.8k | date--; |
1519 | 85.8k | year += date / mx1YearDays; |
1520 | 85.8k | date %= mx1YearDays; |
1521 | 85.8k | year -= mxYearsOffset; |
1522 | 85.8k | leap = mxIsLeapYear(year); |
1523 | 85.8k | date += leap; |
1524 | 85.8k | monthsDays = leap ? gxLeapYearMonthsDays : gxCommonYearMonthsDays; |
1525 | 571k | for (month = 0; month < 11; month++) { |
1526 | 544k | if (date < monthsDays[month + 1]) |
1527 | 59.3k | break; |
1528 | 544k | } |
1529 | 85.8k | date -= monthsDays[month]; |
1530 | 85.8k | dt->date = date + 1; |
1531 | 85.8k | dt->month = month; |
1532 | 85.8k | dt->year = year; |
1533 | 85.8k | if (!utc) { |
1534 | 49.1k | txNumber former = value; |
1535 | 49.1k | txInteger similar; |
1536 | 49.1k | c_time_t time; |
1537 | 49.1k | c_tm tm; |
1538 | 49.1k | similar = fxDateSimilarYear(year); |
1539 | 49.1k | if (similar != year) { |
1540 | 18.5k | dt->year = similar; |
1541 | 18.5k | value = fxDateMerge(dt, 1); |
1542 | 18.5k | } |
1543 | 49.1k | time = (txInteger)c_floor(value / 1000.0); |
1544 | 49.1k | tm = *c_localtime(&time); |
1545 | 49.1k | dt->milliseconds = c_floor(c_fmod(value, 1000.0)); |
1546 | 49.1k | dt->day = tm.tm_wday; |
1547 | 49.1k | dt->seconds = tm.tm_sec; |
1548 | 49.1k | dt->minutes = tm.tm_min; |
1549 | 49.1k | dt->hours = tm.tm_hour; |
1550 | 49.1k | dt->date = tm.tm_mday; |
1551 | 49.1k | dt->month = tm.tm_mon; |
1552 | 49.1k | dt->year = tm.tm_year + 1900 + year - similar; |
1553 | 49.1k | dt->offset = (txInteger)c_trunc((fxDateMerge(dt, 1) - former) / 60000.0); |
1554 | 49.1k | } |
1555 | 85.8k | dt->value = value; |
1556 | 85.8k | } |
1557 | | |
1558 | | |
1559 | | |
1560 | | |