Coverage Report

Created: 2025-12-14 06:18

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
17.6k
{
79
17.6k
  txSlot* slot;
80
17.6k
  mxPush(mxObjectPrototype);
81
17.6k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
82
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMilliseconds), 0, mxID(_getMilliseconds), XS_DONT_ENUM_FLAG);
83
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getSeconds), 0, mxID(_getSeconds), XS_DONT_ENUM_FLAG);
84
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMinutes), 0, mxID(_getMinutes), XS_DONT_ENUM_FLAG);
85
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getHours), 0, mxID(_getHours), XS_DONT_ENUM_FLAG);
86
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDay), 0, mxID(_getDay), XS_DONT_ENUM_FLAG);
87
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDate), 0, mxID(_getDate), XS_DONT_ENUM_FLAG);
88
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMonth), 0, mxID(_getMonth), XS_DONT_ENUM_FLAG);
89
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getYear), 0, mxID(_getYear), XS_DONT_ENUM_FLAG);
90
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getFullYear), 0, mxID(_getFullYear), XS_DONT_ENUM_FLAG);
91
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMilliseconds), 0, mxID(_getUTCMilliseconds), XS_DONT_ENUM_FLAG);
92
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCSeconds), 0, mxID(_getUTCSeconds), XS_DONT_ENUM_FLAG);
93
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMinutes), 0, mxID(_getUTCMinutes), XS_DONT_ENUM_FLAG);
94
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCHours), 0, mxID(_getUTCHours), XS_DONT_ENUM_FLAG);
95
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDay), 0, mxID(_getUTCDay), XS_DONT_ENUM_FLAG);
96
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDate), 0, mxID(_getUTCDate), XS_DONT_ENUM_FLAG);
97
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMonth), 0, mxID(_getUTCMonth), XS_DONT_ENUM_FLAG);
98
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCFullYear), 0, mxID(_getUTCFullYear), XS_DONT_ENUM_FLAG);
99
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_getTime), XS_DONT_ENUM_FLAG);
100
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getTimezoneOffset), 0, mxID(_getTimezoneOffset), XS_DONT_ENUM_FLAG);
101
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setDate), 1, mxID(_setDate), XS_DONT_ENUM_FLAG);
102
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setFullYear), 3, mxID(_setFullYear), XS_DONT_ENUM_FLAG);
103
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setHours), 4, mxID(_setHours), XS_DONT_ENUM_FLAG);
104
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMilliseconds), 1, mxID(_setMilliseconds), XS_DONT_ENUM_FLAG);
105
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMinutes), 3, mxID(_setMinutes), XS_DONT_ENUM_FLAG);
106
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMonth), 2, mxID(_setMonth), XS_DONT_ENUM_FLAG);
107
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setSeconds), 2, mxID(_setSeconds), XS_DONT_ENUM_FLAG);
108
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setTime), 1, mxID(_setTime), XS_DONT_ENUM_FLAG);
109
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setYear), 1, mxID(_setYear), XS_DONT_ENUM_FLAG);
110
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCDate), 1, mxID(_setUTCDate), XS_DONT_ENUM_FLAG);
111
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCFullYear), 3, mxID(_setUTCFullYear), XS_DONT_ENUM_FLAG);
112
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCHours), 4, mxID(_setUTCHours), XS_DONT_ENUM_FLAG);
113
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMilliseconds), 1, mxID(_setUTCMilliseconds), XS_DONT_ENUM_FLAG);
114
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMinutes), 3, mxID(_setUTCMinutes), XS_DONT_ENUM_FLAG);
115
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMonth), 2, mxID(_setUTCMonth), XS_DONT_ENUM_FLAG);
116
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCSeconds), 2, mxID(_setUTCSeconds), XS_DONT_ENUM_FLAG);
117
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toDateString), XS_DONT_ENUM_FLAG);
118
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toISOString), 0, mxID(_toISOString), XS_DONT_ENUM_FLAG);
119
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toJSON), 1, mxID(_toJSON), XS_DONT_ENUM_FLAG);
120
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toLocaleDateString), XS_DONT_ENUM_FLAG);
121
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toLocaleString), XS_DONT_ENUM_FLAG);
122
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toLocaleTimeString), XS_DONT_ENUM_FLAG);
123
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG);
124
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toTimeString), XS_DONT_ENUM_FLAG);
125
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toUTCString), 0, mxID(_toUTCString), XS_DONT_ENUM_FLAG);
126
17.6k
  slot = fxNextSlotProperty(the, slot, slot, mxID(_toGMTString), XS_DONT_ENUM_FLAG);
127
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_valueOf), XS_DONT_ENUM_FLAG);
128
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toPrimitive), 1, mxID(_Symbol_toPrimitive), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
129
17.6k
  mxDatePrototype = *the->stack;
130
17.6k
  slot = fxBuildHostConstructor(the, mxCallback(fx_Date), 7, mxID(_Date));
131
17.6k
  mxDateConstructor = *the->stack;
132
17.6k
  slot = fxLastProperty(the, slot);
133
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_now), 0, mxID(_now), XS_DONT_ENUM_FLAG);
134
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_parse), 1, mxID(_parse), XS_DONT_ENUM_FLAG);
135
17.6k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_UTC), 7, mxID(_UTC), XS_DONT_ENUM_FLAG);
136
17.6k
  mxPop();
137
17.6k
}
138
139
txSlot* fxNewDateInstance(txMachine* the)
140
98.4k
{
141
98.4k
  txSlot* instance;
142
98.4k
  txSlot* property;
143
98.4k
  instance = fxNewObjectInstance(the);
144
98.4k
  property = fxNextNumberProperty(the, instance, 0, XS_NO_ID, XS_INTERNAL_FLAG);
145
98.4k
  property->kind = XS_DATE_KIND;
146
98.4k
  property->value.number = C_NAN;
147
98.4k
  return instance;
148
98.4k
}
149
150
void fx_Date(txMachine* the)
151
108k
{
152
108k
  fx_Date_aux(the, 0);
153
108k
}
154
155
void fx_Date_aux(txMachine* the, txFlag secure)
156
108k
{
157
108k
  txInteger c = mxArgc;
158
108k
  txDateTime dt;
159
108k
  txSlot* instance;
160
108k
  if (mxIsUndefined(mxTarget)) {
161
9.69k
    char buffer[256];
162
9.69k
    txString p = buffer;
163
9.69k
    txDateTime dt;
164
9.69k
    if (secure)
165
0
      mxTypeError("secure mode");
166
9.69k
    mxResult->value.number = fxDateNow();
167
9.69k
    mxResult->kind = XS_NUMBER_KIND;
168
9.69k
    fxDateSplit(mxResult->value.number, 0, &dt);
169
9.69k
    p = fxDatePrintDay(p, dt.day);
170
9.69k
    *p++ = ' ';
171
9.69k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
172
9.69k
    *p++ = ' ';
173
9.69k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
174
9.69k
    *p++ = ' ';
175
9.69k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
176
9.69k
    *p = 0;
177
9.69k
    fxCopyStringC(the, mxResult, buffer);
178
9.69k
    return;
179
9.69k
  }
180
98.4k
  mxPushSlot(mxTarget);
181
98.4k
  fxGetPrototypeFromConstructor(the, &mxDatePrototype);
182
98.4k
  instance = fxNewDateInstance(the);
183
98.4k
  mxPullSlot(mxResult);
184
98.4k
  if (c > 1) {
185
12.4k
    dt.year = fxDateFullYear(the, mxArgv(0));
186
12.4k
    dt.month = fxToNumber(the, mxArgv(1));
187
12.4k
    dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
188
12.4k
    dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
189
12.4k
    dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
190
12.4k
    dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
191
12.4k
    dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
192
12.4k
    instance->next->value.number = fxDateMerge(&dt, 0);
193
12.4k
    return;
194
12.4k
  }
195
86.0k
  if (c > 0) {
196
84.7k
    txSlot* slot = mxArgv(0);
197
84.7k
    if (slot->kind == XS_REFERENCE_KIND) {
198
585
      txSlot* date = slot->value.reference;
199
585
      if ((date->next) && (date->next->kind == XS_DATE_KIND)) {
200
42
        instance->next->value.number = date->next->value.number;
201
42
        return;
202
42
      }
203
585
    }
204
84.7k
    fxToPrimitive(the, slot, XS_NO_HINT);
205
84.7k
    if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
206
7.65k
      mxPushSlot(mxFunction);
207
7.65k
      mxDub();
208
7.65k
      mxGetID(mxID(_parse));
209
7.65k
      mxCall();
210
7.65k
      mxPushSlot(slot);
211
7.65k
      mxRunCount(1);
212
7.65k
      instance->next->value.number = the->stack->value.number;
213
7.65k
      mxPop();
214
7.65k
      return;
215
7.65k
    }
216
77.0k
    instance->next->value.number = fxDateClip(fxToNumber(the, slot));
217
77.0k
    return;
218
84.7k
  }
219
1.32k
  if (secure)
220
0
    mxTypeError("secure mode");
221
1.32k
  instance->next->value.number = fxDateNow();
222
1.32k
}
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
311k
{
242
311k
  txByte c = *theCharacter;
243
311k
  txString p = *theString;
244
311k
  txInteger aResult = c - '0';
245
311k
  c = c_read8(p++);
246
614k
  while (('0' <= c) && (c <= '9')) {
247
303k
#if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_mul_overflow)
248
303k
    if (__builtin_mul_overflow(aResult, 10, &aResult) ||
249
297k
      __builtin_add_overflow(aResult, c - '0', &aResult))
250
8.91k
      *overflow = 1;
251
#else
252
    aResult = (aResult * 10) + c - '0';
253
    if (aResult < 0)
254
      *overflow = 1;
255
#endif
256
303k
    c = c_read8(p++);
257
303k
  }
258
311k
  *theCharacter = c;
259
311k
  *theString = p;
260
311k
  return aResult;
261
311k
}
262
263
txInteger fx_Date_parse_fraction(txByte* theCharacter, txString* theString)
264
763
{
265
763
  txByte c = *theCharacter;
266
763
  txString p = *theString;
267
763
  txNumber fraction = 100;
268
763
  txNumber aResult = ((c - '0') * fraction);
269
763
  c = c_read8(p++);
270
1.62k
  while (('0' <= c) && (c <= '9')) {
271
860
    fraction /= 10;
272
860
    aResult = aResult + ((c - '0') * fraction);
273
860
    c = c_read8(p++);
274
860
  }
275
763
  *theCharacter = c;
276
763
  *theString = p;
277
763
  return (txInteger)c_trunc(aResult);
278
763
}
279
280
void fx_Date_parse(txMachine* the)
281
179k
{
282
591k
  #define mxDayCount 7
283
179k
  static const char* const gxDays[mxDayCount] ICACHE_RODATA_ATTR = {
284
179k
    "monday", 
285
179k
    "tuesday", 
286
179k
    "wednesday", 
287
179k
    "thursday", 
288
179k
    "friday",
289
179k
    "saturday", 
290
179k
    "sunday"
291
179k
  };
292
867k
  #define mxMonthCount 12
293
179k
  static const char* const gxMonths[mxMonthCount] ICACHE_RODATA_ATTR = {
294
179k
    "january",
295
179k
    "february",
296
179k
    "march",
297
179k
    "april",
298
179k
    "may",
299
179k
    "june",
300
179k
    "july",
301
179k
    "august",
302
179k
    "september",
303
179k
    "october",
304
179k
    "november",
305
179k
    "december"
306
179k
  };
307
766k
  #define mxZoneCount 11
308
179k
  static const char* const gxZones[mxZoneCount] ICACHE_RODATA_ATTR = {
309
179k
    "gmt", "ut", "utc",
310
179k
    "est", "edt",
311
179k
    "cst", "cdt",
312
179k
    "mst", "mdt",
313
179k
    "pst", "pdt"
314
179k
  };
315
179k
  static const int gxDeltas[mxZoneCount] ICACHE_XS6RO2_ATTR = {
316
179k
    0, 0, 0,
317
179k
    -5, -4,
318
179k
    -6, -5,
319
179k
    -7, -6,
320
179k
    -8, -7
321
179k
  };
322
  
323
179k
  txString aString;
324
179k
  txBoolean overflow = 0;
325
179k
  txDateTime dt;
326
179k
  txString p;
327
179k
  txString q;
328
179k
  txByte c;
329
179k
  char buffer[10];  /* base type should be the same as txString */
330
179k
  txInteger aComment;
331
179k
  txInteger aDelta;
332
179k
  txInteger aValue;
333
179k
  txSize aLength;
334
179k
  txInteger i;
335
179k
  txInteger yearSign = 1;
336
    
337
179k
  if (mxArgc < 1)
338
1
    goto fail;
339
179k
  aString = fxToString(the, mxArgv(0));
340
  
341
179k
  dt.seconds = -1;
342
179k
  dt.minutes = -1;
343
179k
  dt.hours = -1;
344
179k
  dt.date = -1;
345
179k
  dt.month = -1;
346
179k
  dt.year = -1;
347
179k
  dt.milliseconds = -1;
348
179k
  aComment = 0;
349
179k
  aDelta = -1;
350
351
179k
  c = c_read8(aString++);
352
3.29M
  while (c) {
353
3.28M
    if (c == '(') {
354
263
      aComment++;
355
263
      c = c_read8(aString++);
356
263
      continue;
357
263
    }
358
3.28M
    else if (c == ')') {
359
1.71k
      if (aComment) {
360
245
        aComment--;
361
245
        c = c_read8(aString++);
362
245
        continue;
363
245
      }
364
1.46k
      else
365
1.46k
        goto fail;
366
1.71k
    }
367
3.28M
    else if (aComment) {
368
315
      c = c_read8(aString++);
369
315
      continue;
370
315
    }  
371
    
372
3.28M
    if ((c <= ' ') || (c == ',')) {
373
2.91M
      c = c_read8(aString++);
374
2.91M
      continue;
375
2.91M
    }
376
      
377
374k
    else if ((c == '-') | (c == '+')) {
378
13.0k
            txInteger aSign;
379
13.0k
      if (c == '-')  
380
12.0k
        aSign = -1;
381
927
      else
382
927
        aSign = 1;
383
13.0k
      c = c_read8(aString++);
384
13.0k
      if (('0' <= c) && (c <= '9')) {
385
12.6k
        aValue = fx_Date_parse_number(&c, &aString, &overflow);
386
12.6k
        if (c == '-') {
387
3.97k
          if (dt.year >= 0)
388
611
            goto fail;
389
3.36k
          dt.year = aValue;
390
3.36k
          yearSign = aSign;
391
3.36k
          c = c_read8(aString++);
392
3.36k
          if (('0' <= c) && (c <= '9')) {
393
2.47k
            dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
394
2.47k
            if (c == '-') {
395
1.58k
              c = c_read8(aString++);
396
1.58k
              if (('0' <= c) && (c <= '9'))
397
1.52k
                dt.date = fx_Date_parse_number(&c, &aString, &overflow);
398
58
              else
399
58
                dt.date = 1;
400
1.58k
            }
401
2.47k
          }
402
891
          else
403
891
            dt.month = 0;
404
3.36k
        }
405
8.63k
        else {
406
8.63k
          if ((aDelta != 0) && (aDelta != -1))
407
1.10k
            goto fail;
408
7.52k
          if (c == ':') {
409
684
            aDelta = 60 * aValue;
410
684
            c = c_read8(aString++);
411
684
            if (('0' <= c) && (c <= '9')) {
412
359
              aDelta += fx_Date_parse_number(&c, &aString, &overflow);
413
359
            }
414
684
          }
415
6.84k
          else {
416
6.84k
            if (aValue < 24)
417
4.02k
              aDelta = aValue * 60;
418
2.81k
            else
419
2.81k
              aDelta = (aValue % 100) + ((aValue / 100) * 60);
420
6.84k
          }
421
7.52k
          aDelta *= aSign;
422
7.52k
        }
423
12.6k
      }
424
395
      else
425
395
        goto fail;
426
13.0k
    }    
427
361k
    else if (('0' <= c) && (c <= '9')) {
428
158k
      aValue = fx_Date_parse_number(&c, &aString, &overflow);
429
158k
      if (c == ':') {
430
33.3k
        if (dt.hours >= 0) 
431
238
          goto fail;
432
33.1k
        dt.hours = aValue;  
433
33.1k
        c = c_read8(aString++);
434
33.1k
        if (('0' <= c) && (c <= '9')) {
435
27.2k
          dt.minutes = fx_Date_parse_number(&c, &aString, &overflow);
436
27.2k
          if (c == ':') {
437
25.4k
            c = c_read8(aString++);
438
25.4k
            if (('0' <= c) && (c <= '9')) {
439
24.1k
              dt.seconds = fx_Date_parse_number(&c, &aString, &overflow);
440
24.1k
              if (c == '.') {
441
1.04k
                c = c_read8(aString++);
442
1.04k
                if (('0' <= c) && (c <= '9')) {
443
763
                  dt.milliseconds = fx_Date_parse_fraction(&c, &aString);
444
763
                }
445
1.04k
              }
446
24.1k
            }
447
1.22k
            else
448
1.22k
              dt.seconds = 0;
449
25.4k
          }
450
27.2k
        }
451
5.93k
        else
452
5.93k
          dt.seconds = 0;
453
33.1k
      }
454
125k
      else if (c == '/') {
455
1.56k
        if (dt.year >= 0)
456
468
          goto fail;
457
1.09k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
458
1.09k
        c = c_read8(aString++);
459
1.09k
        if (('0' <= c) && (c <= '9')) {
460
845
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
461
845
          if (c == '/') {
462
200
            c = c_read8(aString++);
463
200
            if (('0' <= c) && (c <= '9')) {
464
56
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
465
56
            }
466
144
            else
467
144
              dt.date = 1;
468
200
          }
469
845
        }
470
252
        else
471
252
          dt.month = 0;
472
1.09k
      }
473
123k
      else if (c == '-') {
474
84.1k
        if (dt.year >= 0)
475
28
          goto fail;
476
84.1k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
477
84.1k
        c = c_read8(aString++);
478
84.1k
        if (('0' <= c) && (c <= '9')) {
479
83.6k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
480
83.6k
          if (c == '-') {
481
435
            c = c_read8(aString++);
482
435
            if (('0' <= c) && (c <= '9'))
483
307
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
484
128
            else
485
128
              dt.date = 1;
486
435
          }
487
83.6k
        }
488
485
        else
489
485
          dt.month = 0;
490
84.1k
      }
491
39.3k
      else {
492
39.3k
        if (aValue < 70) {
493
35.3k
          if (dt.date < 0)
494
32.9k
            dt.date = aValue;
495
2.43k
          else
496
2.43k
            goto fail;
497
35.3k
        }
498
3.98k
        else {
499
3.98k
          if (dt.year < 0)
500
3.59k
            dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
501
392
          else
502
392
            goto fail;
503
3.98k
        }
504
39.3k
      }
505
158k
    }        
506
203k
    else if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'))) {
507
120k
      txSize cmpLength;
508
120k
      p = buffer;
509
120k
      q = p + sizeof(buffer) - 1;
510
586k
      do {
511
586k
        if (p == q) goto fail;
512
539k
        *p++ = (c >= 'a') ? c : (c + ('a' - 'A'));
513
539k
        c = c_read8(aString++);
514
539k
      } while ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')));
515
72.8k
      *p = 0;
516
72.8k
      aLength = mxPtrDiff(p - (txString)buffer);
517
72.8k
      cmpLength = (aLength >= 3) ? aLength : 3;
518
72.8k
      if (c_strcmp("am", buffer) == 0) {
519
3.52k
        if ((dt.hours < 0) || (12 <  dt.hours))
520
1.31k
          goto fail;
521
2.21k
        if (dt.hours == 12)
522
376
          dt.hours = 0;
523
2.21k
        continue;
524
3.52k
      }
525
69.3k
      if (c_strcmp("pm", buffer) == 0) {
526
2.17k
        if ((dt.hours < 0) || (12 <  dt.hours))
527
619
          goto fail;
528
1.55k
        if (dt.hours != 12)
529
1.29k
          dt.hours += 12;
530
1.55k
        continue;
531
2.17k
      }
532
524k
      for (i = 0; i < mxDayCount; i++)
533
460k
        if (c_strncmp(gxDays[i], buffer, cmpLength) == 0)
534
3.53k
          break;
535
67.1k
      if (i < mxDayCount)
536
3.53k
        continue;
537
803k
      for (i = 0; i < mxMonthCount; i++)
538
743k
        if (c_strncmp(gxMonths[i], buffer, cmpLength) == 0)
539
3.66k
          break;
540
63.6k
      if (i < mxMonthCount) {
541
3.66k
        if (dt.month < 0) {
542
3.54k
          dt.month = i;
543
3.54k
          continue;
544
3.54k
        }
545
127
        else
546
127
          goto fail;
547
3.66k
      }
548
706k
      for (i = 0; i < mxZoneCount; i++)
549
648k
        if (c_strcmp(gxZones[i], buffer) == 0)
550
1.39k
          break;
551
59.9k
      if (i < mxZoneCount) {
552
1.39k
        if (aDelta == -1) {
553
303
          aDelta = gxDeltas[i] * 60;
554
303
          continue;
555
303
        }
556
1.08k
        else
557
1.08k
          goto fail;
558
1.39k
      }
559
58.5k
      if (c_strcmp("t", buffer) == 0) {
560
23.8k
        if (dt.year < 0) 
561
259
          goto fail;
562
23.5k
        continue;
563
23.8k
      }
564
34.7k
      if (c_strcmp("z", buffer) == 0) {
565
2.80k
        if (dt.hours < 0) 
566
432
          goto fail;
567
2.37k
        aDelta = 0;
568
2.37k
        continue;
569
2.80k
      }
570
31.9k
      goto fail;
571
34.7k
    }
572
82.8k
    else
573
82.8k
      goto fail;
574
3.28M
  }
575
6.83k
   if (overflow)
576
109
       goto fail;
577
6.73k
   if (dt.year < 0)
578
2.72k
       goto fail;
579
4.00k
  if ((yearSign < 0) && (dt.year == 0))
580
333
       goto fail;
581
3.67k
  if (dt.month < 0)
582
2.06k
    dt.month = 0;
583
3.67k
  if (dt.date < 0)
584
2.57k
    dt.date = 1;
585
3.67k
  if ((aDelta < 0) && (dt.hours < 0) && (dt.minutes < 0) && (dt.seconds < 0) && (dt.milliseconds < 0))
586
368
    aDelta = 0;
587
3.67k
  if (dt.hours < 0)
588
501
    dt.hours = 0;
589
3.67k
  if (dt.minutes < 0)
590
2.69k
    dt.minutes = 0;
591
3.67k
    if (dt.seconds < 0)
592
1.43k
        dt.seconds = 0;
593
3.67k
    if (dt.milliseconds < 0)
594
3.66k
        dt.milliseconds = 0;
595
3.67k
    dt.year *= yearSign;
596
3.67k
  mxResult->value.number = fxDateMerge(&dt, (aDelta != -1) ? 1 : 0);
597
3.67k
  if (aDelta != -1)
598
2.12k
    mxResult->value.number -= (txNumber)aDelta * 60000.0;
599
3.67k
  mxResult->kind = XS_NUMBER_KIND;
600
3.67k
  return;
601
176k
fail:
602
176k
  mxResult->value.number = C_NAN;
603
176k
  mxResult->kind = XS_NUMBER_KIND;
604
  //mxSyntaxError("invalid parameter");
605
176k
}
606
607
void fx_Date_UTC(txMachine* the)
608
4.44k
{
609
4.44k
  txInteger c = mxArgc;
610
4.44k
  txDateTime dt;
611
4.44k
  dt.year = (c > 0) ? fxDateFullYear(the, mxArgv(0)) : C_NAN;
612
4.44k
  dt.month = (c > 1) ? fxToNumber(the, mxArgv(1)) : 0;
613
4.44k
  dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
614
4.44k
  dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
615
4.44k
  dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
616
4.44k
  dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
617
4.44k
  dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
618
4.44k
  mxResult->value.number = fxDateMerge(&dt, 1);
619
4.44k
    mxResult->kind = XS_NUMBER_KIND;
620
4.44k
}
621
622
txBoolean fx_Date_prototype_get_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
623
97.6k
{
624
97.6k
  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
97.6k
  number = slot->value.number;
636
97.6k
  if (c_isnan(number)) {
637
81.5k
    mxResult->value.number = C_NAN;
638
81.5k
    mxResult->kind = XS_NUMBER_KIND;
639
81.5k
    dt->value = C_NAN;
640
81.5k
    return 0;
641
81.5k
  }
642
16.1k
  fxDateSplit(slot->value.number, utc, dt);
643
16.1k
  return 1;
644
97.6k
}
645
646
void fx_Date_prototype_set_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
647
338
{
648
338
  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
338
  if (c_isnan(number))
661
62
    return;
662
276
  if (slot->flag & XS_DONT_SET_FLAG)
663
0
    mxTypeError("this: read-only Date instance");
664
276
  mxResult->value.number = slot->value.number = fxDateMerge(dt, utc);
665
276
  mxResult->kind = XS_NUMBER_KIND;
666
276
}
667
668
void fx_Date_prototype_getMilliseconds(txMachine* the)
669
53
{
670
53
  txDateTime dt;
671
53
  txSlot* slot = fxDateCheck(the);
672
53
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
673
14
    mxResult->value.integer = (txInteger)dt.milliseconds;
674
14
    mxResult->kind = XS_INTEGER_KIND;
675
14
  }
676
53
}
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
30
{
700
30
  txDateTime dt;
701
30
  txSlot* slot = fxDateCheck(the);
702
30
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
703
9
    mxResult->value.integer = (txInteger)dt.hours;
704
9
    mxResult->kind = XS_INTEGER_KIND;
705
9
  }
706
30
}
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
63
{
720
63
  txDateTime dt;
721
63
  txSlot* slot = fxDateCheck(the);
722
63
  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
63
}
727
728
void fx_Date_prototype_getMonth(txMachine* the)
729
29
{
730
29
  txDateTime dt;
731
29
  txSlot* slot = fxDateCheck(the);
732
29
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
733
15
    mxResult->value.integer = (txInteger)dt.month;
734
15
    mxResult->kind = XS_INTEGER_KIND;
735
15
  }
736
29
}
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
26
{
750
26
  txDateTime dt;
751
26
  txSlot* slot = fxDateCheck(the);
752
26
  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
26
}
757
758
void fx_Date_prototype_getUTCMilliseconds(txMachine* the)
759
62
{
760
62
  txDateTime dt;
761
62
  txSlot* slot = fxDateCheck(the);
762
62
  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
62
}
767
768
void fx_Date_prototype_getUTCSeconds(txMachine* the)
769
598
{
770
598
  txDateTime dt;
771
598
  txSlot* slot = fxDateCheck(the);
772
598
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
773
17
    mxResult->value.integer = (txInteger)dt.seconds;
774
17
    mxResult->kind = XS_INTEGER_KIND;
775
17
  }
776
598
}
777
778
void fx_Date_prototype_getUTCMinutes(txMachine* the)
779
37
{
780
37
  txDateTime dt;
781
37
  txSlot* slot = fxDateCheck(the);
782
37
  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
37
}
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
56
{
800
56
  txDateTime dt;
801
56
  txSlot* slot = fxDateCheck(the);
802
56
  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
56
}
807
808
void fx_Date_prototype_getUTCDate(txMachine* the)
809
35
{
810
35
  txDateTime dt;
811
35
  txSlot* slot = fxDateCheck(the);
812
35
  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
35
}
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
52
{
840
52
  txDateTime dt;
841
52
  txSlot* slot = fxDateCheck(the);
842
52
  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
52
}
847
848
void fx_Date_prototype_setMilliseconds(txMachine* the)
849
36
{
850
36
  txInteger c = mxArgc;
851
36
  txDateTime dt;
852
36
  txSlot* slot = fxDateCheck(the);
853
36
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
854
36
  dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
855
36
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
856
36
}
857
858
void fx_Date_prototype_setSeconds(txMachine* the)
859
64
{
860
64
  txInteger c = mxArgc;
861
64
  txDateTime dt;
862
64
  txSlot* slot = fxDateCheck(the);
863
64
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
864
64
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
865
64
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
866
64
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
867
64
}
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
68
{
883
68
  txInteger c = mxArgc;
884
68
  txDateTime dt;
885
68
  txSlot* slot = fxDateCheck(the);
886
68
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
887
68
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
888
68
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
889
68
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
890
68
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
891
68
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
892
68
}
893
894
void fx_Date_prototype_setDate(txMachine* the)
895
36
{
896
36
  txInteger c = mxArgc;
897
36
  txDateTime dt;
898
36
  txSlot* slot = fxDateCheck(the);
899
36
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
900
36
  dt.date = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
901
36
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
902
36
}
903
904
void fx_Date_prototype_setMonth(txMachine* the)
905
55
{
906
55
  txInteger c = mxArgc;
907
55
  txDateTime dt;
908
55
  txSlot* slot = fxDateCheck(the);
909
55
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
910
55
  dt.month = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
911
55
  if (c > 1) dt.date = fxToNumber(the, mxArgv(1));
912
55
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
913
55
}
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
14
{
983
14
  txInteger c = mxArgc;
984
14
  txDateTime dt;
985
14
  txSlot* slot = fxDateCheck(the);
986
14
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
987
14
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
988
14
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
989
14
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
990
14
}
991
992
void fx_Date_prototype_setUTCMinutes(txMachine* the)
993
17
{
994
17
  txInteger c = mxArgc;
995
17
  txDateTime dt;
996
17
  txSlot* slot = fxDateCheck(the);
997
17
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
998
17
  dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
999
17
  if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1));
1000
17
  if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2));
1001
17
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1002
17
}
1003
1004
void fx_Date_prototype_setUTCHours(txMachine* the)
1005
15
{
1006
15
  txInteger c = mxArgc;
1007
15
  txDateTime dt;
1008
15
  txSlot* slot = fxDateCheck(the);
1009
15
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1010
15
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1011
15
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
1012
15
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
1013
15
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
1014
15
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1015
15
}
1016
1017
void fx_Date_prototype_setUTCDate(txMachine* the)
1018
2
{
1019
2
  txInteger c = mxArgc;
1020
2
  txDateTime dt;
1021
2
  txSlot* slot = fxDateCheck(the);
1022
2
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1023
2
  dt.date = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1024
2
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1025
2
}
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
9
{
1040
9
  txInteger c = mxArgc;
1041
9
  txDateTime dt;
1042
9
  txSlot* slot = fxDateCheck(the);
1043
9
  if (c_isnan(slot->value.number)) slot->value.number = 0;
1044
9
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1045
9
  dt.year = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1046
9
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
1047
9
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
1048
9
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1049
9
}
1050
1051
void fx_Date_prototype_toDateString(txMachine* the)
1052
2.41k
{
1053
2.41k
  char buffer[256];
1054
2.41k
  txDateTime dt;
1055
2.41k
  txSlot* slot = fxDateCheck(the);
1056
2.41k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1057
1.57k
    txString p = buffer;
1058
1.57k
    p = fxDatePrintDay(p, dt.day);
1059
1.57k
    *p++ = ' ';
1060
1.57k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1061
1.57k
    *p = 0;
1062
1.57k
  }
1063
838
  else
1064
838
    c_strcpy(buffer, "Invalid Date");
1065
2.41k
  fxCopyStringC(the, mxResult, buffer);
1066
2.41k
}
1067
1068
void fx_Date_prototype_toISOString(txMachine* the)
1069
21
{
1070
21
  char buffer[256];
1071
21
  txDateTime dt;
1072
21
  txSlot* slot = fxDateCheck(the);
1073
21
  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
7
  else
1088
7
        mxRangeError("Invalid Date");
1089
14
  fxCopyStringC(the, mxResult, buffer);
1090
14
}
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
16.4k
{
1114
16.4k
  if (mxIsReference(mxThis)) {
1115
16.4k
    txInteger hint = XS_NO_HINT;
1116
16.4k
    txInteger ids[2], i;
1117
16.4k
    if (mxArgc > 0) {
1118
16.4k
      txSlot* slot = mxArgv(0);
1119
16.4k
      if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
1120
16.4k
        if (!c_strcmp(slot->value.string, "default"))
1121
10.7k
          hint = XS_STRING_HINT;
1122
5.68k
        else if (!c_strcmp(slot->value.string, "number"))
1123
5.60k
          hint = XS_NUMBER_HINT;
1124
75
        else if (!c_strcmp(slot->value.string, "string"))
1125
68
          hint = XS_STRING_HINT;
1126
16.4k
      }
1127
16.4k
    }
1128
16.4k
    if (hint == XS_STRING_HINT) {
1129
10.8k
      ids[0] = mxID(_toString);
1130
10.8k
      ids[1] = mxID(_valueOf);
1131
10.8k
    }
1132
5.62k
    else if (hint == XS_NUMBER_HINT) {
1133
5.60k
      ids[0] = mxID(_valueOf);
1134
5.60k
      ids[1] = mxID(_toString);
1135
5.60k
    }
1136
18
    else
1137
18
        mxTypeError("invalid hint");
1138
16.4k
    for (i = 0; i < 2; i++) {
1139
16.4k
      mxPushSlot(mxThis);
1140
16.4k
      mxPushSlot(mxThis);
1141
16.4k
      mxGetID(ids[i]);
1142
16.4k
      if (fxIsCallable(the, the->stack)) {
1143
16.4k
        mxCall();
1144
16.4k
        mxRunCount(0);
1145
16.4k
        if (mxIsReference(the->stack))
1146
1
          mxPop();
1147
16.4k
        else {
1148
16.4k
          mxPullSlot(mxResult);
1149
16.4k
          return;
1150
16.4k
            }
1151
16.4k
      }
1152
5
      else {
1153
5
        mxPop();
1154
5
        mxPop();
1155
5
      }
1156
16.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
16.4k
}
1166
1167
void fx_Date_prototype_toString(txMachine* the)
1168
10.8k
{
1169
10.8k
  char buffer[256];
1170
10.8k
  txDateTime dt;
1171
10.8k
  txSlot* slot = fxDateCheck(the);
1172
10.8k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1173
9.15k
    txString p = buffer;
1174
9.15k
    p = fxDatePrintDay(p, dt.day);
1175
9.15k
    *p++ = ' ';
1176
9.15k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1177
9.15k
    *p++ = ' ';
1178
9.15k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1179
9.15k
    *p++ = ' ';
1180
9.15k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
1181
9.15k
    *p = 0;
1182
9.15k
  }
1183
1.70k
  else
1184
1.70k
    c_strcpy(buffer, "Invalid Date");
1185
10.8k
  fxCopyStringC(the, mxResult, buffer);
1186
10.8k
}
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
1.65k
{
1207
1.65k
  char buffer[256];
1208
1.65k
  txDateTime dt;
1209
1.65k
  txSlot* slot = fxDateCheck(the);
1210
1.65k
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
1211
1.21k
    txString p = buffer;
1212
1.21k
    p = fxDatePrintDay(p, dt.day);
1213
1.21k
    *p++ = ',';
1214
1.21k
    *p++ = ' ';
1215
1.21k
    p = fxDatePrintDateUTC(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1216
1.21k
    *p++ = ' ';
1217
1.21k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1218
1.21k
    *p++ = ' ';
1219
1.21k
    *p++ = 'G';
1220
1.21k
    *p++ = 'M';
1221
1.21k
    *p++ = 'T';
1222
1.21k
    *p = 0;
1223
1.21k
  }
1224
436
  else
1225
436
    c_strcpy(buffer, "Invalid Date");
1226
1.65k
  fxCopyStringC(the, mxResult, buffer);
1227
1.65k
}
1228
1229
void fx_Date_prototype_valueOf(txMachine* the)
1230
5.99k
{
1231
5.99k
  txSlot* slot = fxDateCheck(the);
1232
5.99k
  mxResult->kind = XS_NUMBER_KIND;
1233
5.99k
  mxResult->value = slot->value;
1234
5.99k
}
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
312k
#define mx1YearDays 365
1259
234k
#define mx4YearsDays ((4 * mx1YearDays) + 1)
1260
156k
#define mx100YearsDays ((25 * mx4YearsDays) - 1)
1261
78.1k
#define mx400YearsDays ((4 * mx100YearsDays) + 1)
1262
145k
#define mxDayMilliseconds 86400000.0
1263
#define mxYearDays(YEAR) \
1264
142k
  ((365 * (YEAR)) + ((YEAR) / 4) - ((YEAR) / 100) + ((YEAR) / 400) + 1)
1265
#define mxIsLeapYear(YEAR) \
1266
58.5k
  (((YEAR) % 4) ? 0 : ((YEAR) % 100) ? 1 : ((YEAR) % 400) ? 0 : 1)
1267
122k
#define mxYearsOffset 400000
1268
1269
txSlot* fxDateCheck(txMachine* the)
1270
106k
{
1271
106k
  txSlot* it = mxThis;
1272
106k
  if (it->kind == XS_REFERENCE_KIND) {
1273
105k
    txSlot* instance = it->value.reference;
1274
105k
    it = instance->next;
1275
105k
    if ((it) && (it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_DATE_KIND))
1276
105k
      return it;
1277
105k
  }
1278
106k
  mxTypeError("this: not a Date instance");
1279
0
  return C_NULL;
1280
106k
}
1281
1282
txNumber fxDateClip(txNumber value)
1283
327k
{
1284
327k
  if (!c_isfinite(value))
1285
76.3k
    value = C_NAN;
1286
250k
  else if (c_fabs(value) > 8.64e15)
1287
3.14k
    value = C_NAN;
1288
247k
  else {
1289
247k
    value = c_trunc(value);
1290
247k
    if (value == 0)
1291
2.08k
      value = 0;
1292
247k
  }
1293
327k
  return value; 
1294
327k
}
1295
1296
txNumber fxDateFullYear(txMachine* the, txSlot* slot)
1297
16.6k
{
1298
16.6k
  txNumber result = fxToNumber(the, slot);
1299
16.6k
  if (c_isfinite(result)) {
1300
15.7k
    txInteger value = fxToInteger(the, slot);
1301
15.7k
    if ((0 <= value) && (value <= 99))
1302
10.8k
      result = 1900 + value;
1303
15.7k
  }
1304
16.6k
  return result;
1305
16.6k
}
1306
1307
txNumber fxDateMerge(txDateTime* dt, txBoolean utc)
1308
66.6k
{
1309
66.6k
  txNumber year, month;
1310
66.6k
  txInteger monthIndex;
1311
66.6k
  txBoolean leap;
1312
66.6k
  txNumber value;
1313
66.6k
  if ((!c_isfinite(dt->year))
1314
65.4k
  || (!c_isfinite(dt->month))
1315
65.2k
  || (!c_isfinite(dt->date))
1316
64.9k
  || (!c_isfinite(dt->hours))
1317
64.8k
  || (!c_isfinite(dt->minutes))
1318
64.8k
  || (!c_isfinite(dt->seconds))
1319
64.6k
  || (!c_isfinite(dt->milliseconds)))
1320
2.16k
    return C_NAN;
1321
64.4k
  year = c_trunc(dt->year);
1322
64.4k
  month = c_trunc(dt->month);
1323
64.4k
  year += c_floor(month / 12);
1324
64.4k
  monthIndex = (txInteger)c_fmod(month, 12.0);
1325
64.4k
  if (monthIndex < 0)
1326
266
    monthIndex += 12;
1327
64.4k
  leap = (c_fmod(year, 4) == 0) && ((c_fmod(year, 100) != 0) || (c_fmod(year, 400) == 0));
1328
64.4k
  year += mxYearsOffset - 1;
1329
64.4k
  value = (365 * year) + c_floor(year / 4) - c_floor(year / 100) + c_floor(year / 400) + 1;
1330
64.4k
  value -= (txNumber)mxYearDays(1970 + mxYearsOffset - 1);
1331
64.4k
  if (leap)
1332
11.7k
    value += gxLeapYearMonthsDays[monthIndex];
1333
52.7k
  else
1334
52.7k
    value += gxCommonYearMonthsDays[monthIndex];
1335
64.4k
  value += c_trunc(dt->date) - 1;
1336
64.4k
  value *= mxDayMilliseconds;
1337
64.4k
  value += c_trunc(dt->hours) * 60 * 60 * 1000;
1338
64.4k
  value += c_trunc(dt->minutes) * 60 * 1000;
1339
64.4k
  value += c_trunc(dt->seconds) * 1000;
1340
64.4k
    value += c_trunc(dt->milliseconds);
1341
64.4k
  if (!utc) {
1342
13.2k
    txNumber former = value;
1343
13.2k
    txInteger similar;
1344
13.2k
    c_tm tm;
1345
13.2k
    c_time_t time;
1346
13.2k
    fxDateSplit(value, 1, dt);
1347
13.2k
    similar = fxDateSimilarYear((txInteger)dt->year);
1348
13.2k
    c_memset(&tm, 0, sizeof(c_tm));
1349
13.2k
    tm.tm_year = similar - 1900;
1350
13.2k
    tm.tm_mon = (txInteger)dt->month;
1351
13.2k
    tm.tm_mday = (txInteger)dt->date;
1352
13.2k
    tm.tm_hour = (txInteger)dt->hours;
1353
13.2k
    tm.tm_min = (txInteger)dt->minutes;
1354
13.2k
    tm.tm_sec = (txInteger)dt->seconds;
1355
13.2k
    tm.tm_isdst =-1;
1356
13.2k
    time = c_mktime(&tm);  
1357
13.2k
    if (time == -1)
1358
0
      value = NAN;
1359
13.2k
    else {
1360
13.2k
      value = (txNumber)time;
1361
13.2k
      value *= 1000;
1362
13.2k
      value += dt->milliseconds;
1363
13.2k
      if (similar != year) {
1364
13.2k
        dt->year = similar;
1365
13.2k
        value += former - fxDateMerge(dt, 1);
1366
13.2k
      }
1367
13.2k
    }
1368
13.2k
  }
1369
64.4k
  return fxDateClip(value);
1370
66.6k
}
1371
1372
txNumber fxDateNow()
1373
185k
{
1374
185k
  c_timeval tv;
1375
185k
  c_gettimeofday(&tv, NULL);
1376
185k
  return fxDateClip(((txNumber)(tv.tv_sec) * 1000.0) + ((txNumber)(tv.tv_usec / 1000)));
1377
185k
}
1378
1379
txString fxDatePrint2Digits(txString p, txInteger value)
1380
141k
{
1381
141k
  *p++ = '0' + value / 10;
1382
141k
  *p++ = '0' + value % 10;
1383
141k
  return p;
1384
141k
}
1385
1386
txString fxDatePrint3Digits(txString p, txInteger value)
1387
21.6k
{
1388
21.6k
  *p++ = '0' + value / 100;
1389
21.6k
  return fxDatePrint2Digits(p, value % 100);
1390
21.6k
}
1391
1392
txString fxDatePrint4Digits(txString p, txInteger value)
1393
21.6k
{
1394
21.6k
  *p++ = '0' + value / 1000;
1395
21.6k
  return fxDatePrint3Digits(p, value % 1000);
1396
21.6k
}
1397
1398
txString fxDatePrintDate(txString p, txInteger year, txInteger month, txInteger date)
1399
20.4k
{
1400
20.4k
  c_strcpy(p, gxMonthNames[month]);
1401
20.4k
  p += 3;
1402
20.4k
  *p++ = ' ';
1403
20.4k
  p = fxDatePrint2Digits(p, date);
1404
20.4k
  *p++ = ' ';
1405
20.4k
  p = fxDatePrintYear(p, year);
1406
20.4k
  return p;
1407
20.4k
}
1408
1409
txString fxDatePrintDateUTC(txString p, txInteger year, txInteger month, txInteger date)
1410
1.21k
{
1411
1.21k
  p = fxDatePrint2Digits(p, date);
1412
1.21k
  *p++ = ' ';
1413
1.21k
  c_strcpy(p, gxMonthNames[month]);
1414
1.21k
  p += 3;
1415
1.21k
  *p++ = ' ';
1416
1.21k
  p = fxDatePrintYear(p, year);
1417
1.21k
  return p;
1418
1.21k
}
1419
1420
txString fxDatePrintDay(txString p, txInteger day)
1421
21.6k
{
1422
21.6k
  c_strcpy(p, gxDayNames[day]);
1423
21.6k
  p += 3;
1424
21.6k
  return p;
1425
21.6k
}
1426
1427
txString fxDatePrintTime(txString p, txInteger hours, txInteger minutes, txInteger seconds)
1428
20.0k
{
1429
20.0k
  p = fxDatePrint2Digits(p, hours);
1430
20.0k
  *p++ = ':';
1431
20.0k
  p = fxDatePrint2Digits(p, minutes);
1432
20.0k
  *p++ = ':';
1433
20.0k
  p = fxDatePrint2Digits(p, seconds);
1434
20.0k
  return p;
1435
20.0k
}
1436
1437
txString fxDatePrintTimezone(txString p, txInteger offset)
1438
18.8k
{
1439
18.8k
  *p++ = 'G';
1440
18.8k
  *p++ = 'M';
1441
18.8k
  *p++ = 'T';
1442
18.8k
  if (offset < 0) {
1443
0
    offset = 0 - offset;
1444
0
    *p++ = '-';
1445
0
  }
1446
18.8k
  else
1447
18.8k
    *p++ = '+';
1448
18.8k
  p = fxDatePrint2Digits(p, offset / 60);
1449
18.8k
  p = fxDatePrint2Digits(p, offset % 60);
1450
18.8k
  return p;
1451
18.8k
}
1452
1453
txString fxDatePrintYear(txString p, txInteger value)
1454
21.6k
{
1455
21.6k
  if ((value < 0) || (9999 < value)) {
1456
2.79k
    if (value < 0) {
1457
1.37k
      *p++ = '-';
1458
1.37k
      value = -value;
1459
1.37k
    }
1460
1.42k
    else
1461
1.42k
      *p++ = '+';
1462
2.79k
    if (99999 < value) {
1463
1.12k
      *p++ = '0' + value / 100000;
1464
1.12k
      value %= 100000;
1465
1.12k
    }
1466
2.79k
    if (9999 < value) {
1467
1.86k
      *p++ = '0' + value / 10000;
1468
1.86k
      value %= 10000;
1469
1.86k
    }
1470
2.79k
  }
1471
21.6k
  return fxDatePrint4Digits(p, value);
1472
21.6k
}
1473
1474
txInteger fxDateSimilarYear(txInteger year)
1475
37.6k
{
1476
37.6k
  txInteger leap, day;
1477
37.6k
  if ((1970 <= year) && (year < 2038))
1478
18.1k
    return year;
1479
19.4k
  leap = mxIsLeapYear(year);
1480
19.4k
  year += mxYearsOffset - 1;
1481
19.4k
  day = mxYearDays(year) - mxYearDays(1970 + mxYearsOffset - 1);
1482
19.4k
  day = (day + 4) % 7;
1483
19.4k
  if (day < 0)
1484
15.3k
    day += 7; 
1485
19.4k
  return (leap) ? gxSimilarLeapYears[day] : gxSimilarCommonYears[day];
1486
37.6k
}
1487
1488
void fxDateSplit(txNumber value, txBoolean utc, txDateTime* dt)
1489
39.0k
{
1490
39.0k
  txInteger date, time, year, leap, month;
1491
39.0k
  const txInteger* monthsDays;
1492
39.0k
  date = (txInteger)c_trunc(value / mxDayMilliseconds);
1493
39.0k
  time = (txInteger)c_fmod(value, mxDayMilliseconds);
1494
39.0k
  if (time < 0) {
1495
2.55k
    date--;
1496
2.55k
    time += (txInteger)mxDayMilliseconds;
1497
2.55k
  }
1498
39.0k
  dt->offset = 0;
1499
39.0k
  dt->day = (date + 4) % 7;
1500
39.0k
  if (dt->day < 0)
1501
13.6k
    dt->day += 7; 
1502
39.0k
  dt->milliseconds = time % 1000;
1503
39.0k
  time /= 1000;
1504
39.0k
  dt->seconds = time % 60;
1505
39.0k
  time /= 60;
1506
39.0k
  dt->minutes = time % 60;
1507
39.0k
  time /= 60;
1508
39.0k
  dt->hours = time;
1509
39.0k
    date += mxYearDays(1970 + mxYearsOffset);
1510
39.0k
    year = 400 * (date / mx400YearsDays);
1511
39.0k
  date %= mx400YearsDays;
1512
39.0k
  date--;
1513
39.0k
  year += 100 * (date / mx100YearsDays);
1514
39.0k
  date %= mx100YearsDays;
1515
39.0k
  date++;
1516
39.0k
  year += 4 * (date / mx4YearsDays);
1517
39.0k
  date %= mx4YearsDays;
1518
39.0k
  date--;
1519
39.0k
  year += date / mx1YearDays;
1520
39.0k
    date %= mx1YearDays;
1521
39.0k
  year -= mxYearsOffset;
1522
39.0k
  leap = mxIsLeapYear(year);
1523
39.0k
    date += leap;
1524
39.0k
    monthsDays = leap ? gxLeapYearMonthsDays : gxCommonYearMonthsDays;
1525
281k
    for (month = 0; month < 11; month++) {
1526
269k
      if (date < monthsDays[month + 1])
1527
26.4k
        break;
1528
269k
    }
1529
39.0k
    date -= monthsDays[month];
1530
39.0k
  dt->date = date + 1;
1531
39.0k
  dt->month = month;
1532
39.0k
  dt->year = year;
1533
39.0k
  if (!utc) {
1534
24.4k
    txNumber former = value;
1535
24.4k
    txInteger similar;
1536
24.4k
    c_time_t time;
1537
24.4k
    c_tm tm;
1538
24.4k
    similar = fxDateSimilarYear(year);
1539
24.4k
    if (similar != year) {
1540
8.17k
      dt->year = similar;
1541
8.17k
      value = fxDateMerge(dt, 1);
1542
8.17k
    }
1543
24.4k
    time = (txInteger)c_floor(value / 1000.0);
1544
24.4k
    tm = *c_localtime(&time);
1545
24.4k
    dt->milliseconds = c_floor(c_fmod(value, 1000.0));
1546
24.4k
    dt->day = tm.tm_wday;
1547
24.4k
    dt->seconds = tm.tm_sec;
1548
24.4k
    dt->minutes = tm.tm_min;
1549
24.4k
    dt->hours = tm.tm_hour;
1550
24.4k
    dt->date = tm.tm_mday;
1551
24.4k
    dt->month = tm.tm_mon;
1552
24.4k
    dt->year = tm.tm_year + 1900 + year - similar;
1553
24.4k
    dt->offset = (txInteger)c_trunc((fxDateMerge(dt, 1) - former) / 60000.0);
1554
24.4k
  }
1555
39.0k
  dt->value = value;
1556
39.0k
}
1557
1558
1559
1560