Coverage Report

Created: 2025-12-30 07:10

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