Coverage Report

Created: 2026-01-10 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
16.3k
{
79
16.3k
  txSlot* slot;
80
16.3k
  mxPush(mxObjectPrototype);
81
16.3k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
82
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMilliseconds), 0, mxID(_getMilliseconds), XS_DONT_ENUM_FLAG);
83
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getSeconds), 0, mxID(_getSeconds), XS_DONT_ENUM_FLAG);
84
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMinutes), 0, mxID(_getMinutes), XS_DONT_ENUM_FLAG);
85
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getHours), 0, mxID(_getHours), XS_DONT_ENUM_FLAG);
86
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDay), 0, mxID(_getDay), XS_DONT_ENUM_FLAG);
87
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDate), 0, mxID(_getDate), XS_DONT_ENUM_FLAG);
88
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMonth), 0, mxID(_getMonth), XS_DONT_ENUM_FLAG);
89
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getYear), 0, mxID(_getYear), XS_DONT_ENUM_FLAG);
90
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getFullYear), 0, mxID(_getFullYear), XS_DONT_ENUM_FLAG);
91
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMilliseconds), 0, mxID(_getUTCMilliseconds), XS_DONT_ENUM_FLAG);
92
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCSeconds), 0, mxID(_getUTCSeconds), XS_DONT_ENUM_FLAG);
93
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMinutes), 0, mxID(_getUTCMinutes), XS_DONT_ENUM_FLAG);
94
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCHours), 0, mxID(_getUTCHours), XS_DONT_ENUM_FLAG);
95
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDay), 0, mxID(_getUTCDay), XS_DONT_ENUM_FLAG);
96
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDate), 0, mxID(_getUTCDate), XS_DONT_ENUM_FLAG);
97
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMonth), 0, mxID(_getUTCMonth), XS_DONT_ENUM_FLAG);
98
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCFullYear), 0, mxID(_getUTCFullYear), XS_DONT_ENUM_FLAG);
99
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_getTime), XS_DONT_ENUM_FLAG);
100
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getTimezoneOffset), 0, mxID(_getTimezoneOffset), XS_DONT_ENUM_FLAG);
101
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setDate), 1, mxID(_setDate), XS_DONT_ENUM_FLAG);
102
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setFullYear), 3, mxID(_setFullYear), XS_DONT_ENUM_FLAG);
103
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setHours), 4, mxID(_setHours), XS_DONT_ENUM_FLAG);
104
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMilliseconds), 1, mxID(_setMilliseconds), XS_DONT_ENUM_FLAG);
105
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMinutes), 3, mxID(_setMinutes), XS_DONT_ENUM_FLAG);
106
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMonth), 2, mxID(_setMonth), XS_DONT_ENUM_FLAG);
107
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setSeconds), 2, mxID(_setSeconds), XS_DONT_ENUM_FLAG);
108
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setTime), 1, mxID(_setTime), XS_DONT_ENUM_FLAG);
109
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setYear), 1, mxID(_setYear), XS_DONT_ENUM_FLAG);
110
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCDate), 1, mxID(_setUTCDate), XS_DONT_ENUM_FLAG);
111
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCFullYear), 3, mxID(_setUTCFullYear), XS_DONT_ENUM_FLAG);
112
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCHours), 4, mxID(_setUTCHours), XS_DONT_ENUM_FLAG);
113
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMilliseconds), 1, mxID(_setUTCMilliseconds), XS_DONT_ENUM_FLAG);
114
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMinutes), 3, mxID(_setUTCMinutes), XS_DONT_ENUM_FLAG);
115
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMonth), 2, mxID(_setUTCMonth), XS_DONT_ENUM_FLAG);
116
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCSeconds), 2, mxID(_setUTCSeconds), XS_DONT_ENUM_FLAG);
117
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toDateString), XS_DONT_ENUM_FLAG);
118
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toISOString), 0, mxID(_toISOString), XS_DONT_ENUM_FLAG);
119
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toJSON), 1, mxID(_toJSON), XS_DONT_ENUM_FLAG);
120
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toLocaleDateString), XS_DONT_ENUM_FLAG);
121
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toLocaleString), XS_DONT_ENUM_FLAG);
122
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toLocaleTimeString), XS_DONT_ENUM_FLAG);
123
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG);
124
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toTimeString), XS_DONT_ENUM_FLAG);
125
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toUTCString), 0, mxID(_toUTCString), XS_DONT_ENUM_FLAG);
126
16.3k
  slot = fxNextSlotProperty(the, slot, slot, mxID(_toGMTString), XS_DONT_ENUM_FLAG);
127
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_valueOf), XS_DONT_ENUM_FLAG);
128
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toPrimitive), 1, mxID(_Symbol_toPrimitive), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
129
16.3k
  mxDatePrototype = *the->stack;
130
16.3k
  slot = fxBuildHostConstructor(the, mxCallback(fx_Date), 7, mxID(_Date));
131
16.3k
  mxDateConstructor = *the->stack;
132
16.3k
  slot = fxLastProperty(the, slot);
133
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_now), 0, mxID(_now), XS_DONT_ENUM_FLAG);
134
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_parse), 1, mxID(_parse), XS_DONT_ENUM_FLAG);
135
16.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_UTC), 7, mxID(_UTC), XS_DONT_ENUM_FLAG);
136
16.3k
  mxPop();
137
16.3k
}
138
139
txSlot* fxNewDateInstance(txMachine* the)
140
95.5k
{
141
95.5k
  txSlot* instance;
142
95.5k
  txSlot* property;
143
95.5k
  instance = fxNewObjectInstance(the);
144
95.5k
  property = fxNextNumberProperty(the, instance, 0, XS_NO_ID, XS_INTERNAL_FLAG);
145
95.5k
  property->kind = XS_DATE_KIND;
146
95.5k
  property->value.number = C_NAN;
147
95.5k
  return instance;
148
95.5k
}
149
150
void fx_Date(txMachine* the)
151
102k
{
152
102k
  fx_Date_aux(the, 0);
153
102k
}
154
155
void fx_Date_aux(txMachine* the, txFlag secure)
156
102k
{
157
102k
  txInteger c = mxArgc;
158
102k
  txDateTime dt;
159
102k
  txSlot* instance;
160
102k
  if (mxIsUndefined(mxTarget)) {
161
6.45k
    char buffer[256];
162
6.45k
    txString p = buffer;
163
6.45k
    txDateTime dt;
164
6.45k
    if (secure)
165
0
      mxTypeError("secure mode");
166
6.45k
    mxResult->value.number = fxDateNow();
167
6.45k
    mxResult->kind = XS_NUMBER_KIND;
168
6.45k
    fxDateSplit(mxResult->value.number, 0, &dt);
169
6.45k
    p = fxDatePrintDay(p, dt.day);
170
6.45k
    *p++ = ' ';
171
6.45k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
172
6.45k
    *p++ = ' ';
173
6.45k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
174
6.45k
    *p++ = ' ';
175
6.45k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
176
6.45k
    *p = 0;
177
6.45k
    fxCopyStringC(the, mxResult, buffer);
178
6.45k
    return;
179
6.45k
  }
180
95.5k
  mxPushSlot(mxTarget);
181
95.5k
  fxGetPrototypeFromConstructor(the, &mxDatePrototype);
182
95.5k
  instance = fxNewDateInstance(the);
183
95.5k
  mxPullSlot(mxResult);
184
95.5k
  if (c > 1) {
185
11.6k
    dt.year = fxDateFullYear(the, mxArgv(0));
186
11.6k
    dt.month = fxToNumber(the, mxArgv(1));
187
11.6k
    dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
188
11.6k
    dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
189
11.6k
    dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
190
11.6k
    dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
191
11.6k
    dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
192
11.6k
    instance->next->value.number = fxDateMerge(&dt, 0);
193
11.6k
    return;
194
11.6k
  }
195
83.8k
  if (c > 0) {
196
82.3k
    txSlot* slot = mxArgv(0);
197
82.3k
    if (slot->kind == XS_REFERENCE_KIND) {
198
224
      txSlot* date = slot->value.reference;
199
224
      if ((date->next) && (date->next->kind == XS_DATE_KIND)) {
200
16
        instance->next->value.number = date->next->value.number;
201
16
        return;
202
16
      }
203
224
    }
204
82.2k
    fxToPrimitive(the, slot, XS_NO_HINT);
205
82.2k
    if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
206
5.13k
      mxPushSlot(mxFunction);
207
5.13k
      mxDub();
208
5.13k
      mxGetID(mxID(_parse));
209
5.13k
      mxCall();
210
5.13k
      mxPushSlot(slot);
211
5.13k
      mxRunCount(1);
212
5.13k
      instance->next->value.number = the->stack->value.number;
213
5.13k
      mxPop();
214
5.13k
      return;
215
5.13k
    }
216
77.1k
    instance->next->value.number = fxDateClip(fxToNumber(the, slot));
217
77.1k
    return;
218
82.2k
  }
219
1.59k
  if (secure)
220
0
    mxTypeError("secure mode");
221
1.59k
  instance->next->value.number = fxDateNow();
222
1.59k
}
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
358k
{
242
358k
  txByte c = *theCharacter;
243
358k
  txString p = *theString;
244
358k
  txInteger aResult = c - '0';
245
358k
  c = c_read8(p++);
246
708k
  while (('0' <= c) && (c <= '9')) {
247
349k
#if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_mul_overflow)
248
349k
    if (__builtin_mul_overflow(aResult, 10, &aResult) ||
249
341k
      __builtin_add_overflow(aResult, c - '0', &aResult))
250
10.6k
      *overflow = 1;
251
#else
252
    aResult = (aResult * 10) + c - '0';
253
    if (aResult < 0)
254
      *overflow = 1;
255
#endif
256
349k
    c = c_read8(p++);
257
349k
  }
258
358k
  *theCharacter = c;
259
358k
  *theString = p;
260
358k
  return aResult;
261
358k
}
262
263
txInteger fx_Date_parse_fraction(txByte* theCharacter, txString* theString)
264
484
{
265
484
  txByte c = *theCharacter;
266
484
  txString p = *theString;
267
484
  txNumber fraction = 100;
268
484
  txNumber aResult = ((c - '0') * fraction);
269
484
  c = c_read8(p++);
270
561
  while (('0' <= c) && (c <= '9')) {
271
77
    fraction /= 10;
272
77
    aResult = aResult + ((c - '0') * fraction);
273
77
    c = c_read8(p++);
274
77
  }
275
484
  *theCharacter = c;
276
484
  *theString = p;
277
484
  return (txInteger)c_trunc(aResult);
278
484
}
279
280
void fx_Date_parse(txMachine* the)
281
154k
{
282
467k
  #define mxDayCount 7
283
154k
  static const char* const gxDays[mxDayCount] ICACHE_RODATA_ATTR = {
284
154k
    "monday", 
285
154k
    "tuesday", 
286
154k
    "wednesday", 
287
154k
    "thursday", 
288
154k
    "friday",
289
154k
    "saturday", 
290
154k
    "sunday"
291
154k
  };
292
678k
  #define mxMonthCount 12
293
154k
  static const char* const gxMonths[mxMonthCount] ICACHE_RODATA_ATTR = {
294
154k
    "january",
295
154k
    "february",
296
154k
    "march",
297
154k
    "april",
298
154k
    "may",
299
154k
    "june",
300
154k
    "july",
301
154k
    "august",
302
154k
    "september",
303
154k
    "october",
304
154k
    "november",
305
154k
    "december"
306
154k
  };
307
599k
  #define mxZoneCount 11
308
154k
  static const char* const gxZones[mxZoneCount] ICACHE_RODATA_ATTR = {
309
154k
    "gmt", "ut", "utc",
310
154k
    "est", "edt",
311
154k
    "cst", "cdt",
312
154k
    "mst", "mdt",
313
154k
    "pst", "pdt"
314
154k
  };
315
154k
  static const int gxDeltas[mxZoneCount] ICACHE_XS6RO2_ATTR = {
316
154k
    0, 0, 0,
317
154k
    -5, -4,
318
154k
    -6, -5,
319
154k
    -7, -6,
320
154k
    -8, -7
321
154k
  };
322
  
323
154k
  txString aString;
324
154k
  txBoolean overflow = 0;
325
154k
  txDateTime dt;
326
154k
  txString p;
327
154k
  txString q;
328
154k
  txByte c;
329
154k
  char buffer[10];  /* base type should be the same as txString */
330
154k
  txInteger aComment;
331
154k
  txInteger aDelta;
332
154k
  txInteger aValue;
333
154k
  txSize aLength;
334
154k
  txInteger i;
335
154k
  txInteger yearSign = 1;
336
    
337
154k
  if (mxArgc < 1)
338
0
    goto fail;
339
154k
  aString = fxToString(the, mxArgv(0));
340
  
341
154k
  dt.seconds = -1;
342
154k
  dt.minutes = -1;
343
154k
  dt.hours = -1;
344
154k
  dt.date = -1;
345
154k
  dt.month = -1;
346
154k
  dt.year = -1;
347
154k
  dt.milliseconds = -1;
348
154k
  aComment = 0;
349
154k
  aDelta = -1;
350
351
154k
  c = c_read8(aString++);
352
3.77M
  while (c) {
353
3.77M
    if (c == '(') {
354
419
      aComment++;
355
419
      c = c_read8(aString++);
356
419
      continue;
357
419
    }
358
3.76M
    else if (c == ')') {
359
1.31k
      if (aComment) {
360
320
        aComment--;
361
320
        c = c_read8(aString++);
362
320
        continue;
363
320
      }
364
998
      else
365
998
        goto fail;
366
1.31k
    }
367
3.76M
    else if (aComment) {
368
4.19k
      c = c_read8(aString++);
369
4.19k
      continue;
370
4.19k
    }  
371
    
372
3.76M
    if ((c <= ' ') || (c == ',')) {
373
3.40M
      c = c_read8(aString++);
374
3.40M
      continue;
375
3.40M
    }
376
      
377
364k
    else if ((c == '-') | (c == '+')) {
378
7.16k
            txInteger aSign;
379
7.16k
      if (c == '-')  
380
6.90k
        aSign = -1;
381
264
      else
382
264
        aSign = 1;
383
7.16k
      c = c_read8(aString++);
384
7.16k
      if (('0' <= c) && (c <= '9')) {
385
6.98k
        aValue = fx_Date_parse_number(&c, &aString, &overflow);
386
6.98k
        if (c == '-') {
387
2.71k
          if (dt.year >= 0)
388
477
            goto fail;
389
2.23k
          dt.year = aValue;
390
2.23k
          yearSign = aSign;
391
2.23k
          c = c_read8(aString++);
392
2.23k
          if (('0' <= c) && (c <= '9')) {
393
1.78k
            dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
394
1.78k
            if (c == '-') {
395
1.15k
              c = c_read8(aString++);
396
1.15k
              if (('0' <= c) && (c <= '9'))
397
1.09k
                dt.date = fx_Date_parse_number(&c, &aString, &overflow);
398
59
              else
399
59
                dt.date = 1;
400
1.15k
            }
401
1.78k
          }
402
451
          else
403
451
            dt.month = 0;
404
2.23k
        }
405
4.27k
        else {
406
4.27k
          if ((aDelta != 0) && (aDelta != -1))
407
204
            goto fail;
408
4.07k
          if (c == ':') {
409
648
            aDelta = 60 * aValue;
410
648
            c = c_read8(aString++);
411
648
            if (('0' <= c) && (c <= '9')) {
412
331
              aDelta += fx_Date_parse_number(&c, &aString, &overflow);
413
331
            }
414
648
          }
415
3.42k
          else {
416
3.42k
            if (aValue < 24)
417
2.11k
              aDelta = aValue * 60;
418
1.30k
            else
419
1.30k
              aDelta = (aValue % 100) + ((aValue / 100) * 60);
420
3.42k
          }
421
4.07k
          aDelta *= aSign;
422
4.07k
        }
423
6.98k
      }
424
177
      else
425
177
        goto fail;
426
7.16k
    }    
427
357k
    else if (('0' <= c) && (c <= '9')) {
428
179k
      aValue = fx_Date_parse_number(&c, &aString, &overflow);
429
179k
      if (c == ':') {
430
47.2k
        if (dt.hours >= 0) 
431
47
          goto fail;
432
47.2k
        dt.hours = aValue;  
433
47.2k
        c = c_read8(aString++);
434
47.2k
        if (('0' <= c) && (c <= '9')) {
435
43.2k
          dt.minutes = fx_Date_parse_number(&c, &aString, &overflow);
436
43.2k
          if (c == ':') {
437
42.0k
            c = c_read8(aString++);
438
42.0k
            if (('0' <= c) && (c <= '9')) {
439
23.8k
              dt.seconds = fx_Date_parse_number(&c, &aString, &overflow);
440
23.8k
              if (c == '.') {
441
995
                c = c_read8(aString++);
442
995
                if (('0' <= c) && (c <= '9')) {
443
484
                  dt.milliseconds = fx_Date_parse_fraction(&c, &aString);
444
484
                }
445
995
              }
446
23.8k
            }
447
18.2k
            else
448
18.2k
              dt.seconds = 0;
449
42.0k
          }
450
43.2k
        }
451
4.02k
        else
452
4.02k
          dt.seconds = 0;
453
47.2k
      }
454
132k
      else if (c == '/') {
455
1.86k
        if (dt.year >= 0)
456
482
          goto fail;
457
1.38k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
458
1.38k
        c = c_read8(aString++);
459
1.38k
        if (('0' <= c) && (c <= '9')) {
460
1.07k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
461
1.07k
          if (c == '/') {
462
201
            c = c_read8(aString++);
463
201
            if (('0' <= c) && (c <= '9')) {
464
55
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
465
55
            }
466
146
            else
467
146
              dt.date = 1;
468
201
          }
469
1.07k
        }
470
309
        else
471
309
          dt.month = 0;
472
1.38k
      }
473
130k
      else if (c == '-') {
474
100k
        if (dt.year >= 0)
475
28
          goto fail;
476
100k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
477
100k
        c = c_read8(aString++);
478
100k
        if (('0' <= c) && (c <= '9')) {
479
99.9k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
480
99.9k
          if (c == '-') {
481
190
            c = c_read8(aString++);
482
190
            if (('0' <= c) && (c <= '9'))
483
151
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
484
39
            else
485
39
              dt.date = 1;
486
190
          }
487
99.9k
        }
488
549
        else
489
549
          dt.month = 0;
490
100k
      }
491
30.1k
      else {
492
30.1k
        if (aValue < 70) {
493
9.49k
          if (dt.date < 0)
494
7.03k
            dt.date = aValue;
495
2.46k
          else
496
2.46k
            goto fail;
497
9.49k
        }
498
20.6k
        else {
499
20.6k
          if (dt.year < 0)
500
2.85k
            dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
501
17.7k
          else
502
17.7k
            goto fail;
503
20.6k
        }
504
30.1k
      }
505
179k
    }        
506
177k
    else if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'))) {
507
94.9k
      txSize cmpLength;
508
94.9k
      p = buffer;
509
94.9k
      q = p + sizeof(buffer) - 1;
510
463k
      do {
511
463k
        if (p == q) goto fail;
512
425k
        *p++ = (c >= 'a') ? c : (c + ('a' - 'A'));
513
425k
        c = c_read8(aString++);
514
425k
      } while ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')));
515
57.0k
      *p = 0;
516
57.0k
      aLength = mxPtrDiff(p - (txString)buffer);
517
57.0k
      cmpLength = (aLength >= 3) ? aLength : 3;
518
57.0k
      if (c_strcmp("am", buffer) == 0) {
519
2.20k
        if ((dt.hours < 0) || (12 <  dt.hours))
520
280
          goto fail;
521
1.92k
        if (dt.hours == 12)
522
517
          dt.hours = 0;
523
1.92k
        continue;
524
2.20k
      }
525
54.8k
      if (c_strcmp("pm", buffer) == 0) {
526
1.63k
        if ((dt.hours < 0) || (12 <  dt.hours))
527
100
          goto fail;
528
1.53k
        if (dt.hours != 12)
529
759
          dt.hours += 12;
530
1.53k
        continue;
531
1.63k
      }
532
413k
      for (i = 0; i < mxDayCount; i++)
533
363k
        if (c_strncmp(gxDays[i], buffer, cmpLength) == 0)
534
3.09k
          break;
535
53.1k
      if (i < mxDayCount)
536
3.09k
        continue;
537
627k
      for (i = 0; i < mxMonthCount; i++)
538
581k
        if (c_strncmp(gxMonths[i], buffer, cmpLength) == 0)
539
3.44k
          break;
540
50.0k
      if (i < mxMonthCount) {
541
3.44k
        if (dt.month < 0) {
542
3.10k
          dt.month = i;
543
3.10k
          continue;
544
3.10k
        }
545
348
        else
546
348
          goto fail;
547
3.44k
      }
548
552k
      for (i = 0; i < mxZoneCount; i++)
549
506k
        if (c_strcmp(gxZones[i], buffer) == 0)
550
666
          break;
551
46.6k
      if (i < mxZoneCount) {
552
666
        if (aDelta == -1) {
553
38
          aDelta = gxDeltas[i] * 60;
554
38
          continue;
555
38
        }
556
628
        else
557
628
          goto fail;
558
666
      }
559
45.9k
      if (c_strcmp("t", buffer) == 0) {
560
40.1k
        if (dt.year < 0) 
561
160
          goto fail;
562
40.0k
        continue;
563
40.1k
      }
564
5.80k
      if (c_strcmp("z", buffer) == 0) {
565
1.91k
        if (dt.hours < 0) 
566
708
          goto fail;
567
1.20k
        aDelta = 0;
568
1.20k
        continue;
569
1.91k
      }
570
3.88k
      goto fail;
571
5.80k
    }
572
82.3k
    else
573
82.3k
      goto fail;
574
3.76M
  }
575
5.39k
   if (overflow)
576
71
       goto fail;
577
5.32k
   if (dt.year < 0)
578
2.28k
       goto fail;
579
3.03k
  if ((yearSign < 0) && (dt.year == 0))
580
84
       goto fail;
581
2.95k
  if (dt.month < 0)
582
1.72k
    dt.month = 0;
583
2.95k
  if (dt.date < 0)
584
2.10k
    dt.date = 1;
585
2.95k
  if ((aDelta < 0) && (dt.hours < 0) && (dt.minutes < 0) && (dt.seconds < 0) && (dt.milliseconds < 0))
586
340
    aDelta = 0;
587
2.95k
  if (dt.hours < 0)
588
473
    dt.hours = 0;
589
2.95k
  if (dt.minutes < 0)
590
2.35k
    dt.minutes = 0;
591
2.95k
    if (dt.seconds < 0)
592
1.03k
        dt.seconds = 0;
593
2.95k
    if (dt.milliseconds < 0)
594
2.94k
        dt.milliseconds = 0;
595
2.95k
    dt.year *= yearSign;
596
2.95k
  mxResult->value.number = fxDateMerge(&dt, (aDelta != -1) ? 1 : 0);
597
2.95k
  if (aDelta != -1)
598
1.33k
    mxResult->value.number -= (txNumber)aDelta * 60000.0;
599
2.95k
  mxResult->kind = XS_NUMBER_KIND;
600
2.95k
  return;
601
151k
fail:
602
151k
  mxResult->value.number = C_NAN;
603
151k
  mxResult->kind = XS_NUMBER_KIND;
604
  //mxSyntaxError("invalid parameter");
605
151k
}
606
607
void fx_Date_UTC(txMachine* the)
608
28.9k
{
609
28.9k
  txInteger c = mxArgc;
610
28.9k
  txDateTime dt;
611
28.9k
  dt.year = (c > 0) ? fxDateFullYear(the, mxArgv(0)) : C_NAN;
612
28.9k
  dt.month = (c > 1) ? fxToNumber(the, mxArgv(1)) : 0;
613
28.9k
  dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
614
28.9k
  dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
615
28.9k
  dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
616
28.9k
  dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
617
28.9k
  dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
618
28.9k
  mxResult->value.number = fxDateMerge(&dt, 1);
619
28.9k
    mxResult->kind = XS_NUMBER_KIND;
620
28.9k
}
621
622
txBoolean fx_Date_prototype_get_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
623
95.4k
{
624
95.4k
  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
95.4k
  number = slot->value.number;
636
95.4k
  if (c_isnan(number)) {
637
80.5k
    mxResult->value.number = C_NAN;
638
80.5k
    mxResult->kind = XS_NUMBER_KIND;
639
80.5k
    dt->value = C_NAN;
640
80.5k
    return 0;
641
80.5k
  }
642
14.9k
  fxDateSplit(slot->value.number, utc, dt);
643
14.9k
  return 1;
644
95.4k
}
645
646
void fx_Date_prototype_set_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
647
320
{
648
320
  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
320
  if (c_isnan(number))
661
60
    return;
662
260
  if (slot->flag & XS_DONT_SET_FLAG)
663
0
    mxTypeError("this: read-only Date instance");
664
260
  mxResult->value.number = slot->value.number = fxDateMerge(dt, utc);
665
260
  mxResult->kind = XS_NUMBER_KIND;
666
260
}
667
668
void fx_Date_prototype_getMilliseconds(txMachine* the)
669
60
{
670
60
  txDateTime dt;
671
60
  txSlot* slot = fxDateCheck(the);
672
60
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
673
16
    mxResult->value.integer = (txInteger)dt.milliseconds;
674
16
    mxResult->kind = XS_INTEGER_KIND;
675
16
  }
676
60
}
677
678
void fx_Date_prototype_getSeconds(txMachine* the)
679
28
{
680
28
  txDateTime dt;
681
28
  txSlot* slot = fxDateCheck(the);
682
28
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
683
9
    mxResult->value.integer = (txInteger)dt.seconds;
684
9
    mxResult->kind = XS_INTEGER_KIND;
685
9
  }
686
28
}
687
688
void fx_Date_prototype_getMinutes(txMachine* the)
689
31
{
690
31
  txDateTime dt;
691
31
  txSlot* slot = fxDateCheck(the);
692
31
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
693
12
    mxResult->value.integer = (txInteger)dt.minutes;
694
12
    mxResult->kind = XS_INTEGER_KIND;
695
12
  }
696
31
}
697
698
void fx_Date_prototype_getHours(txMachine* the)
699
36
{
700
36
  txDateTime dt;
701
36
  txSlot* slot = fxDateCheck(the);
702
36
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
703
15
    mxResult->value.integer = (txInteger)dt.hours;
704
15
    mxResult->kind = XS_INTEGER_KIND;
705
15
  }
706
36
}
707
708
void fx_Date_prototype_getDay(txMachine* the)
709
76.0k
{
710
76.0k
  txDateTime dt;
711
76.0k
  txSlot* slot = fxDateCheck(the);
712
76.0k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
713
15
    mxResult->value.integer = dt.day;
714
15
    mxResult->kind = XS_INTEGER_KIND;
715
15
  }
716
76.0k
}
717
718
void fx_Date_prototype_getDate(txMachine* the)
719
33
{
720
33
  txDateTime dt;
721
33
  txSlot* slot = fxDateCheck(the);
722
33
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
723
9
    mxResult->value.integer = (txInteger)dt.date;
724
9
    mxResult->kind = XS_INTEGER_KIND;
725
9
  }
726
33
}
727
728
void fx_Date_prototype_getMonth(txMachine* the)
729
31
{
730
31
  txDateTime dt;
731
31
  txSlot* slot = fxDateCheck(the);
732
31
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
733
16
    mxResult->value.integer = (txInteger)dt.month;
734
16
    mxResult->kind = XS_INTEGER_KIND;
735
16
  }
736
31
}
737
738
void fx_Date_prototype_getYear(txMachine* the)
739
1
{
740
1
  txDateTime dt;
741
1
  txSlot* slot = fxDateCheck(the);
742
1
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
743
0
    mxResult->value.integer = (txInteger)dt.year - 1900;
744
0
    mxResult->kind = XS_INTEGER_KIND;
745
0
  }
746
1
}
747
748
void fx_Date_prototype_getFullYear(txMachine* the)
749
24
{
750
24
  txDateTime dt;
751
24
  txSlot* slot = fxDateCheck(the);
752
24
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
753
6
    mxResult->value.integer = (txInteger)dt.year;
754
6
    mxResult->kind = XS_INTEGER_KIND;
755
6
  }
756
24
}
757
758
void fx_Date_prototype_getUTCMilliseconds(txMachine* the)
759
64
{
760
64
  txDateTime dt;
761
64
  txSlot* slot = fxDateCheck(the);
762
64
  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
64
}
767
768
void fx_Date_prototype_getUTCSeconds(txMachine* the)
769
592
{
770
592
  txDateTime dt;
771
592
  txSlot* slot = fxDateCheck(the);
772
592
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
773
15
    mxResult->value.integer = (txInteger)dt.seconds;
774
15
    mxResult->kind = XS_INTEGER_KIND;
775
15
  }
776
592
}
777
778
void fx_Date_prototype_getUTCMinutes(txMachine* the)
779
35
{
780
35
  txDateTime dt;
781
35
  txSlot* slot = fxDateCheck(the);
782
35
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
783
13
    mxResult->value.integer = (txInteger)dt.minutes;
784
13
    mxResult->kind = XS_INTEGER_KIND;
785
13
  }
786
35
}
787
788
void fx_Date_prototype_getUTCHours(txMachine* the)
789
38
{
790
38
  txDateTime dt;
791
38
  txSlot* slot = fxDateCheck(the);
792
38
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
793
15
    mxResult->value.integer = (txInteger)dt.hours;
794
15
    mxResult->kind = XS_INTEGER_KIND;
795
15
  }
796
38
}
797
798
void fx_Date_prototype_getUTCDay(txMachine* the)
799
54
{
800
54
  txDateTime dt;
801
54
  txSlot* slot = fxDateCheck(the);
802
54
  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
54
}
807
808
void fx_Date_prototype_getUTCDate(txMachine* the)
809
34
{
810
34
  txDateTime dt;
811
34
  txSlot* slot = fxDateCheck(the);
812
34
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
813
14
    mxResult->value.integer = (txInteger)dt.date;
814
14
    mxResult->kind = XS_INTEGER_KIND;
815
14
  }
816
34
}
817
818
void fx_Date_prototype_getUTCMonth(txMachine* the)
819
35
{
820
35
  txDateTime dt;
821
35
  txSlot* slot = fxDateCheck(the);
822
35
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
823
11
    mxResult->value.integer = (txInteger)dt.month;
824
11
    mxResult->kind = XS_INTEGER_KIND;
825
11
  }
826
35
}
827
828
void fx_Date_prototype_getUTCFullYear(txMachine* the)
829
45
{
830
45
  txDateTime dt;
831
45
  txSlot* slot = fxDateCheck(the);
832
45
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
833
11
    mxResult->value.integer = (txInteger)dt.year;
834
11
    mxResult->kind = XS_INTEGER_KIND;
835
11
  }
836
45
}
837
838
void fx_Date_prototype_getTimezoneOffset(txMachine* the)
839
48
{
840
48
  txDateTime dt;
841
48
  txSlot* slot = fxDateCheck(the);
842
48
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
843
13
    mxResult->value.integer = 0 - dt.offset;
844
13
    mxResult->kind = XS_INTEGER_KIND;
845
13
  }
846
48
}
847
848
void fx_Date_prototype_setMilliseconds(txMachine* the)
849
39
{
850
39
  txInteger c = mxArgc;
851
39
  txDateTime dt;
852
39
  txSlot* slot = fxDateCheck(the);
853
39
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
854
39
  dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
855
39
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
856
39
}
857
858
void fx_Date_prototype_setSeconds(txMachine* the)
859
59
{
860
59
  txInteger c = mxArgc;
861
59
  txDateTime dt;
862
59
  txSlot* slot = fxDateCheck(the);
863
59
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
864
59
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
865
59
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
866
59
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
867
59
}
868
869
void fx_Date_prototype_setMinutes(txMachine* the)
870
1.89k
{
871
1.89k
  txInteger c = mxArgc;
872
1.89k
  txDateTime dt;
873
1.89k
  txSlot* slot = fxDateCheck(the);
874
1.89k
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
875
1.89k
  dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
876
1.89k
  if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1));
877
1.89k
  if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2));
878
1.89k
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
879
1.89k
}
880
881
void fx_Date_prototype_setHours(txMachine* the)
882
66
{
883
66
  txInteger c = mxArgc;
884
66
  txDateTime dt;
885
66
  txSlot* slot = fxDateCheck(the);
886
66
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
887
66
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
888
66
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
889
66
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
890
66
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
891
66
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
892
66
}
893
894
void fx_Date_prototype_setDate(txMachine* the)
895
48
{
896
48
  txInteger c = mxArgc;
897
48
  txDateTime dt;
898
48
  txSlot* slot = fxDateCheck(the);
899
48
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
900
48
  dt.date = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
901
48
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
902
48
}
903
904
void fx_Date_prototype_setMonth(txMachine* the)
905
52
{
906
52
  txInteger c = mxArgc;
907
52
  txDateTime dt;
908
52
  txSlot* slot = fxDateCheck(the);
909
52
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
910
52
  dt.month = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
911
52
  if (c > 1) dt.date = fxToNumber(the, mxArgv(1));
912
52
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
913
52
}
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.89k
{
934
1.89k
  txInteger c = mxArgc;
935
1.89k
  txDateTime dt;
936
1.89k
  txSlot* slot = fxDateCheck(the);
937
1.89k
  if (c_isnan(slot->value.number)) {
938
8
    slot->value.number = 0;
939
8
    fx_Date_prototype_get_aux(the, &dt, 1, slot);
940
8
  }
941
1.88k
  else
942
1.88k
    fx_Date_prototype_get_aux(the, &dt, 0, slot);
943
1.89k
  dt.year = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
944
1.89k
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
945
1.89k
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
946
1.89k
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
947
1.89k
}
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
10
{
983
10
  txInteger c = mxArgc;
984
10
  txDateTime dt;
985
10
  txSlot* slot = fxDateCheck(the);
986
10
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
987
10
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
988
10
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
989
10
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
990
10
}
991
992
void fx_Date_prototype_setUTCMinutes(txMachine* the)
993
21
{
994
21
  txInteger c = mxArgc;
995
21
  txDateTime dt;
996
21
  txSlot* slot = fxDateCheck(the);
997
21
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
998
21
  dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
999
21
  if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1));
1000
21
  if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2));
1001
21
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1002
21
}
1003
1004
void fx_Date_prototype_setUTCHours(txMachine* the)
1005
18
{
1006
18
  txInteger c = mxArgc;
1007
18
  txDateTime dt;
1008
18
  txSlot* slot = fxDateCheck(the);
1009
18
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1010
18
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1011
18
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
1012
18
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
1013
18
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
1014
18
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1015
18
}
1016
1017
void fx_Date_prototype_setUTCDate(txMachine* the)
1018
3
{
1019
3
  txInteger c = mxArgc;
1020
3
  txDateTime dt;
1021
3
  txSlot* slot = fxDateCheck(the);
1022
3
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1023
3
  dt.date = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1024
3
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1025
3
}
1026
1027
void fx_Date_prototype_setUTCMonth(txMachine* the)
1028
1.85k
{
1029
1.85k
  txInteger c = mxArgc;
1030
1.85k
  txDateTime dt;
1031
1.85k
  txSlot* slot = fxDateCheck(the);
1032
1.85k
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1033
1.85k
  dt.month = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1034
1.85k
  if (c > 1) dt.date = fxToNumber(the, mxArgv(1));
1035
1.85k
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1036
1.85k
}
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
1.36k
{
1053
1.36k
  char buffer[256];
1054
1.36k
  txDateTime dt;
1055
1.36k
  txSlot* slot = fxDateCheck(the);
1056
1.36k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1057
1.06k
    txString p = buffer;
1058
1.06k
    p = fxDatePrintDay(p, dt.day);
1059
1.06k
    *p++ = ' ';
1060
1.06k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1061
1.06k
    *p = 0;
1062
1.06k
  }
1063
304
  else
1064
304
    c_strcpy(buffer, "Invalid Date");
1065
1.36k
  fxCopyStringC(the, mxResult, buffer);
1066
1.36k
}
1067
1068
void fx_Date_prototype_toISOString(txMachine* the)
1069
20
{
1070
20
  char buffer[256];
1071
20
  txDateTime dt;
1072
20
  txSlot* slot = fxDateCheck(the);
1073
20
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
1074
14
    txString p = buffer;
1075
14
    p = fxDatePrintYear(p, (txInteger)dt.year);
1076
14
    *p++ = '-';
1077
14
    p = fxDatePrint2Digits(p, (txInteger)dt.month + 1);
1078
14
    *p++ = '-';
1079
14
    p = fxDatePrint2Digits(p, (txInteger)dt.date);
1080
14
    *p++ = 'T';
1081
14
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1082
14
    *p++ = '.';
1083
14
    p = fxDatePrint3Digits(p, (txInteger)dt.milliseconds);
1084
14
    *p++ = 'Z';
1085
14
    *p = 0;
1086
14
  }
1087
6
  else
1088
6
        mxRangeError("Invalid Date");
1089
14
  fxCopyStringC(the, mxResult, buffer);
1090
14
}
1091
1092
void fx_Date_prototype_toJSON(txMachine* the)
1093
17
{
1094
17
  fxToInstance(the, mxThis);
1095
17
  mxPushSlot(mxThis);
1096
17
  fxToPrimitive(the, the->stack, XS_NUMBER_HINT);
1097
17
  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
14
  else {   
1102
14
    mxPop();
1103
14
    mxPushSlot(mxThis);
1104
14
    mxDub();
1105
14
    mxGetID(mxID(_toISOString));
1106
14
    mxCall();
1107
14
    mxRunCount(0);
1108
14
    mxPullSlot(mxResult);
1109
14
  }
1110
17
}
1111
1112
void fx_Date_prototype_toPrimitive(txMachine* the)
1113
15.4k
{
1114
15.4k
  if (mxIsReference(mxThis)) {
1115
15.4k
    txInteger hint = XS_NO_HINT;
1116
15.4k
    txInteger ids[2], i;
1117
15.4k
    if (mxArgc > 0) {
1118
15.4k
      txSlot* slot = mxArgv(0);
1119
15.4k
      if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
1120
15.4k
        if (!c_strcmp(slot->value.string, "default"))
1121
10.3k
          hint = XS_STRING_HINT;
1122
5.10k
        else if (!c_strcmp(slot->value.string, "number"))
1123
4.90k
          hint = XS_NUMBER_HINT;
1124
196
        else if (!c_strcmp(slot->value.string, "string"))
1125
189
          hint = XS_STRING_HINT;
1126
15.4k
      }
1127
15.4k
    }
1128
15.4k
    if (hint == XS_STRING_HINT) {
1129
10.5k
      ids[0] = mxID(_toString);
1130
10.5k
      ids[1] = mxID(_valueOf);
1131
10.5k
    }
1132
4.92k
    else if (hint == XS_NUMBER_HINT) {
1133
4.90k
      ids[0] = mxID(_valueOf);
1134
4.90k
      ids[1] = mxID(_toString);
1135
4.90k
    }
1136
18
    else
1137
18
        mxTypeError("invalid hint");
1138
15.4k
    for (i = 0; i < 2; i++) {
1139
15.4k
      mxPushSlot(mxThis);
1140
15.4k
      mxPushSlot(mxThis);
1141
15.4k
      mxGetID(ids[i]);
1142
15.4k
      if (fxIsCallable(the, the->stack)) {
1143
15.4k
        mxCall();
1144
15.4k
        mxRunCount(0);
1145
15.4k
        if (mxIsReference(the->stack))
1146
1
          mxPop();
1147
15.4k
        else {
1148
15.4k
          mxPullSlot(mxResult);
1149
15.4k
          return;
1150
15.4k
            }
1151
15.4k
      }
1152
5
      else {
1153
5
        mxPop();
1154
5
        mxPop();
1155
5
      }
1156
15.4k
    }
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
15.4k
}
1166
1167
void fx_Date_prototype_toString(txMachine* the)
1168
10.5k
{
1169
10.5k
  char buffer[256];
1170
10.5k
  txDateTime dt;
1171
10.5k
  txSlot* slot = fxDateCheck(the);
1172
10.5k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1173
8.88k
    txString p = buffer;
1174
8.88k
    p = fxDatePrintDay(p, dt.day);
1175
8.88k
    *p++ = ' ';
1176
8.88k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1177
8.88k
    *p++ = ' ';
1178
8.88k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1179
8.88k
    *p++ = ' ';
1180
8.88k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
1181
8.88k
    *p = 0;
1182
8.88k
  }
1183
1.67k
  else
1184
1.67k
    c_strcpy(buffer, "Invalid Date");
1185
10.5k
  fxCopyStringC(the, mxResult, buffer);
1186
10.5k
}
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
823
{
1207
823
  char buffer[256];
1208
823
  txDateTime dt;
1209
823
  txSlot* slot = fxDateCheck(the);
1210
823
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
1211
815
    txString p = buffer;
1212
815
    p = fxDatePrintDay(p, dt.day);
1213
815
    *p++ = ',';
1214
815
    *p++ = ' ';
1215
815
    p = fxDatePrintDateUTC(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1216
815
    *p++ = ' ';
1217
815
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1218
815
    *p++ = ' ';
1219
815
    *p++ = 'G';
1220
815
    *p++ = 'M';
1221
815
    *p++ = 'T';
1222
815
    *p = 0;
1223
815
  }
1224
8
  else
1225
8
    c_strcpy(buffer, "Invalid Date");
1226
823
  fxCopyStringC(the, mxResult, buffer);
1227
823
}
1228
1229
void fx_Date_prototype_valueOf(txMachine* the)
1230
5.29k
{
1231
5.29k
  txSlot* slot = fxDateCheck(the);
1232
5.29k
  mxResult->kind = XS_NUMBER_KIND;
1233
5.29k
  mxResult->value = slot->value;
1234
5.29k
}
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
269k
#define mx1YearDays 365
1259
202k
#define mx4YearsDays ((4 * mx1YearDays) + 1)
1260
134k
#define mx100YearsDays ((25 * mx4YearsDays) - 1)
1261
67.4k
#define mx400YearsDays ((4 * mx100YearsDays) + 1)
1262
151k
#define mxDayMilliseconds 86400000.0
1263
#define mxYearDays(YEAR) \
1264
155k
  ((365 * (YEAR)) + ((YEAR) / 4) - ((YEAR) / 100) + ((YEAR) / 400) + 1)
1265
#define mxIsLeapYear(YEAR) \
1266
53.5k
  (((YEAR) % 4) ? 0 : ((YEAR) % 100) ? 1 : ((YEAR) % 400) ? 0 : 1)
1267
136k
#define mxYearsOffset 400000
1268
1269
txSlot* fxDateCheck(txMachine* the)
1270
103k
{
1271
103k
  txSlot* it = mxThis;
1272
103k
  if (it->kind == XS_REFERENCE_KIND) {
1273
102k
    txSlot* instance = it->value.reference;
1274
102k
    it = instance->next;
1275
102k
    if ((it) && (it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_DATE_KIND))
1276
102k
      return it;
1277
102k
  }
1278
103k
  mxTypeError("this: not a Date instance");
1279
0
  return C_NULL;
1280
103k
}
1281
1282
txNumber fxDateClip(txNumber value)
1283
177k
{
1284
177k
  if (!c_isfinite(value))
1285
76.3k
    value = C_NAN;
1286
101k
  else if (c_fabs(value) > 8.64e15)
1287
3.03k
    value = C_NAN;
1288
98.2k
  else {
1289
98.2k
    value = c_trunc(value);
1290
98.2k
    if (value == 0)
1291
2.04k
      value = 0;
1292
98.2k
  }
1293
177k
  return value; 
1294
177k
}
1295
1296
txNumber fxDateFullYear(txMachine* the, txSlot* slot)
1297
40.4k
{
1298
40.4k
  txNumber result = fxToNumber(the, slot);
1299
40.4k
  if (c_isfinite(result)) {
1300
39.4k
    txInteger value = fxToInteger(the, slot);
1301
39.4k
    if ((0 <= value) && (value <= 99))
1302
35.1k
      result = 1900 + value;
1303
39.4k
  }
1304
40.4k
  return result;
1305
40.4k
}
1306
1307
txNumber fxDateMerge(txDateTime* dt, txBoolean utc)
1308
84.9k
{
1309
84.9k
  txNumber year, month;
1310
84.9k
  txInteger monthIndex;
1311
84.9k
  txBoolean leap;
1312
84.9k
  txNumber value;
1313
84.9k
  if ((!c_isfinite(dt->year))
1314
83.7k
  || (!c_isfinite(dt->month))
1315
83.4k
  || (!c_isfinite(dt->date))
1316
83.1k
  || (!c_isfinite(dt->hours))
1317
83.1k
  || (!c_isfinite(dt->minutes))
1318
83.0k
  || (!c_isfinite(dt->seconds))
1319
82.7k
  || (!c_isfinite(dt->milliseconds)))
1320
2.39k
    return C_NAN;
1321
82.5k
  year = c_trunc(dt->year);
1322
82.5k
  month = c_trunc(dt->month);
1323
82.5k
  year += c_floor(month / 12);
1324
82.5k
  monthIndex = (txInteger)c_fmod(month, 12.0);
1325
82.5k
  if (monthIndex < 0)
1326
407
    monthIndex += 12;
1327
82.5k
  leap = (c_fmod(year, 4) == 0) && ((c_fmod(year, 100) != 0) || (c_fmod(year, 400) == 0));
1328
82.5k
  year += mxYearsOffset - 1;
1329
82.5k
  value = (365 * year) + c_floor(year / 4) - c_floor(year / 100) + c_floor(year / 400) + 1;
1330
82.5k
  value -= (txNumber)mxYearDays(1970 + mxYearsOffset - 1);
1331
82.5k
  if (leap)
1332
11.4k
    value += gxLeapYearMonthsDays[monthIndex];
1333
71.1k
  else
1334
71.1k
    value += gxCommonYearMonthsDays[monthIndex];
1335
82.5k
  value += c_trunc(dt->date) - 1;
1336
82.5k
  value *= mxDayMilliseconds;
1337
82.5k
  value += c_trunc(dt->hours) * 60 * 60 * 1000;
1338
82.5k
  value += c_trunc(dt->minutes) * 60 * 1000;
1339
82.5k
  value += c_trunc(dt->seconds) * 1000;
1340
82.5k
    value += c_trunc(dt->milliseconds);
1341
82.5k
  if (!utc) {
1342
12.3k
    txNumber former = value;
1343
12.3k
    txInteger similar;
1344
12.3k
    c_tm tm;
1345
12.3k
    c_time_t time;
1346
12.3k
    fxDateSplit(value, 1, dt);
1347
12.3k
    similar = fxDateSimilarYear((txInteger)dt->year);
1348
12.3k
    c_memset(&tm, 0, sizeof(c_tm));
1349
12.3k
    tm.tm_year = similar - 1900;
1350
12.3k
    tm.tm_mon = (txInteger)dt->month;
1351
12.3k
    tm.tm_mday = (txInteger)dt->date;
1352
12.3k
    tm.tm_hour = (txInteger)dt->hours;
1353
12.3k
    tm.tm_min = (txInteger)dt->minutes;
1354
12.3k
    tm.tm_sec = (txInteger)dt->seconds;
1355
12.3k
    tm.tm_isdst =-1;
1356
12.3k
    time = c_mktime(&tm);  
1357
12.3k
    if (time == -1)
1358
0
      value = NAN;
1359
12.3k
    else {
1360
12.3k
      value = (txNumber)time;
1361
12.3k
      value *= 1000;
1362
12.3k
      value += dt->milliseconds;
1363
12.3k
      if (similar != year) {
1364
12.3k
        dt->year = similar;
1365
12.3k
        value += former - fxDateMerge(dt, 1);
1366
12.3k
      }
1367
12.3k
    }
1368
12.3k
  }
1369
82.5k
  return fxDateClip(value);
1370
84.9k
}
1371
1372
txNumber fxDateNow()
1373
17.9k
{
1374
17.9k
  c_timeval tv;
1375
17.9k
  c_gettimeofday(&tv, NULL);
1376
17.9k
  return fxDateClip(((txNumber)(tv.tv_sec) * 1000.0) + ((txNumber)(tv.tv_usec / 1000)));
1377
17.9k
}
1378
1379
txString fxDatePrint2Digits(txString p, txInteger value)
1380
113k
{
1381
113k
  *p++ = '0' + value / 10;
1382
113k
  *p++ = '0' + value % 10;
1383
113k
  return p;
1384
113k
}
1385
1386
txString fxDatePrint3Digits(txString p, txInteger value)
1387
17.2k
{
1388
17.2k
  *p++ = '0' + value / 100;
1389
17.2k
  return fxDatePrint2Digits(p, value % 100);
1390
17.2k
}
1391
1392
txString fxDatePrint4Digits(txString p, txInteger value)
1393
17.2k
{
1394
17.2k
  *p++ = '0' + value / 1000;
1395
17.2k
  return fxDatePrint3Digits(p, value % 1000);
1396
17.2k
}
1397
1398
txString fxDatePrintDate(txString p, txInteger year, txInteger month, txInteger date)
1399
16.4k
{
1400
16.4k
  c_strcpy(p, gxMonthNames[month]);
1401
16.4k
  p += 3;
1402
16.4k
  *p++ = ' ';
1403
16.4k
  p = fxDatePrint2Digits(p, date);
1404
16.4k
  *p++ = ' ';
1405
16.4k
  p = fxDatePrintYear(p, year);
1406
16.4k
  return p;
1407
16.4k
}
1408
1409
txString fxDatePrintDateUTC(txString p, txInteger year, txInteger month, txInteger date)
1410
815
{
1411
815
  p = fxDatePrint2Digits(p, date);
1412
815
  *p++ = ' ';
1413
815
  c_strcpy(p, gxMonthNames[month]);
1414
815
  p += 3;
1415
815
  *p++ = ' ';
1416
815
  p = fxDatePrintYear(p, year);
1417
815
  return p;
1418
815
}
1419
1420
txString fxDatePrintDay(txString p, txInteger day)
1421
17.2k
{
1422
17.2k
  c_strcpy(p, gxDayNames[day]);
1423
17.2k
  p += 3;
1424
17.2k
  return p;
1425
17.2k
}
1426
1427
txString fxDatePrintTime(txString p, txInteger hours, txInteger minutes, txInteger seconds)
1428
16.1k
{
1429
16.1k
  p = fxDatePrint2Digits(p, hours);
1430
16.1k
  *p++ = ':';
1431
16.1k
  p = fxDatePrint2Digits(p, minutes);
1432
16.1k
  *p++ = ':';
1433
16.1k
  p = fxDatePrint2Digits(p, seconds);
1434
16.1k
  return p;
1435
16.1k
}
1436
1437
txString fxDatePrintTimezone(txString p, txInteger offset)
1438
15.3k
{
1439
15.3k
  *p++ = 'G';
1440
15.3k
  *p++ = 'M';
1441
15.3k
  *p++ = 'T';
1442
15.3k
  if (offset < 0) {
1443
0
    offset = 0 - offset;
1444
0
    *p++ = '-';
1445
0
  }
1446
15.3k
  else
1447
15.3k
    *p++ = '+';
1448
15.3k
  p = fxDatePrint2Digits(p, offset / 60);
1449
15.3k
  p = fxDatePrint2Digits(p, offset % 60);
1450
15.3k
  return p;
1451
15.3k
}
1452
1453
txString fxDatePrintYear(txString p, txInteger value)
1454
17.2k
{
1455
17.2k
  if ((value < 0) || (9999 < value)) {
1456
1.63k
    if (value < 0) {
1457
703
      *p++ = '-';
1458
703
      value = -value;
1459
703
    }
1460
936
    else
1461
936
      *p++ = '+';
1462
1.63k
    if (99999 < value) {
1463
542
      *p++ = '0' + value / 100000;
1464
542
      value %= 100000;
1465
542
    }
1466
1.63k
    if (9999 < value) {
1467
1.26k
      *p++ = '0' + value / 10000;
1468
1.26k
      value %= 10000;
1469
1.26k
    }
1470
1.63k
  }
1471
17.2k
  return fxDatePrint4Digits(p, value);
1472
17.2k
}
1473
1474
txInteger fxDateSimilarYear(txInteger year)
1475
32.6k
{
1476
32.6k
  txInteger leap, day;
1477
32.6k
  if ((1970 <= year) && (year < 2038))
1478
12.8k
    return year;
1479
19.8k
  leap = mxIsLeapYear(year);
1480
19.8k
  year += mxYearsOffset - 1;
1481
19.8k
  day = mxYearDays(year) - mxYearDays(1970 + mxYearsOffset - 1);
1482
19.8k
  day = (day + 4) % 7;
1483
19.8k
  if (day < 0)
1484
16.2k
    day += 7; 
1485
19.8k
  return (leap) ? gxSimilarLeapYears[day] : gxSimilarCommonYears[day];
1486
32.6k
}
1487
1488
void fxDateSplit(txNumber value, txBoolean utc, txDateTime* dt)
1489
33.7k
{
1490
33.7k
  txInteger date, time, year, leap, month;
1491
33.7k
  const txInteger* monthsDays;
1492
33.7k
  date = (txInteger)c_trunc(value / mxDayMilliseconds);
1493
33.7k
  time = (txInteger)c_fmod(value, mxDayMilliseconds);
1494
33.7k
  if (time < 0) {
1495
1.37k
    date--;
1496
1.37k
    time += (txInteger)mxDayMilliseconds;
1497
1.37k
  }
1498
33.7k
  dt->offset = 0;
1499
33.7k
  dt->day = (date + 4) % 7;
1500
33.7k
  if (dt->day < 0)
1501
14.3k
    dt->day += 7; 
1502
33.7k
  dt->milliseconds = time % 1000;
1503
33.7k
  time /= 1000;
1504
33.7k
  dt->seconds = time % 60;
1505
33.7k
  time /= 60;
1506
33.7k
  dt->minutes = time % 60;
1507
33.7k
  time /= 60;
1508
33.7k
  dt->hours = time;
1509
33.7k
    date += mxYearDays(1970 + mxYearsOffset);
1510
33.7k
    year = 400 * (date / mx400YearsDays);
1511
33.7k
  date %= mx400YearsDays;
1512
33.7k
  date--;
1513
33.7k
  year += 100 * (date / mx100YearsDays);
1514
33.7k
  date %= mx100YearsDays;
1515
33.7k
  date++;
1516
33.7k
  year += 4 * (date / mx4YearsDays);
1517
33.7k
  date %= mx4YearsDays;
1518
33.7k
  date--;
1519
33.7k
  year += date / mx1YearDays;
1520
33.7k
    date %= mx1YearDays;
1521
33.7k
  year -= mxYearsOffset;
1522
33.7k
  leap = mxIsLeapYear(year);
1523
33.7k
    date += leap;
1524
33.7k
    monthsDays = leap ? gxLeapYearMonthsDays : gxCommonYearMonthsDays;
1525
150k
    for (month = 0; month < 11; month++) {
1526
148k
      if (date < monthsDays[month + 1])
1527
31.8k
        break;
1528
148k
    }
1529
33.7k
    date -= monthsDays[month];
1530
33.7k
  dt->date = date + 1;
1531
33.7k
  dt->month = month;
1532
33.7k
  dt->year = year;
1533
33.7k
  if (!utc) {
1534
20.3k
    txNumber former = value;
1535
20.3k
    txInteger similar;
1536
20.3k
    c_time_t time;
1537
20.3k
    c_tm tm;
1538
20.3k
    similar = fxDateSimilarYear(year);
1539
20.3k
    if (similar != year) {
1540
8.38k
      dt->year = similar;
1541
8.38k
      value = fxDateMerge(dt, 1);
1542
8.38k
    }
1543
20.3k
    time = (txInteger)c_floor(value / 1000.0);
1544
20.3k
    tm = *c_localtime(&time);
1545
20.3k
    dt->milliseconds = c_floor(c_fmod(value, 1000.0));
1546
20.3k
    dt->day = tm.tm_wday;
1547
20.3k
    dt->seconds = tm.tm_sec;
1548
20.3k
    dt->minutes = tm.tm_min;
1549
20.3k
    dt->hours = tm.tm_hour;
1550
20.3k
    dt->date = tm.tm_mday;
1551
20.3k
    dt->month = tm.tm_mon;
1552
20.3k
    dt->year = tm.tm_year + 1900 + year - similar;
1553
20.3k
    dt->offset = (txInteger)c_trunc((fxDateMerge(dt, 1) - former) / 60000.0);
1554
20.3k
  }
1555
33.7k
  dt->value = value;
1556
33.7k
}
1557
1558
1559
1560