Coverage Report

Created: 2026-06-10 07:01

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