Coverage Report

Created: 2026-10-17 07:25

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
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
205k
{
141
205k
  txSlot* instance;
142
205k
  txSlot* property;
143
205k
  instance = fxNewObjectInstance(the);
144
205k
  property = fxNextNumberProperty(the, instance, 0, XS_NO_ID, XS_INTERNAL_FLAG);
145
205k
  property->kind = XS_DATE_KIND;
146
205k
  property->value.number = C_NAN;
147
205k
  return instance;
148
205k
}
149
150
void fx_Date(txMachine* the)
151
225k
{
152
225k
  fx_Date_aux(the, 0);
153
225k
}
154
155
void fx_Date_aux(txMachine* the, txFlag secure)
156
225k
{
157
225k
  txInteger c = mxArgc;
158
225k
  txDateTime dt;
159
225k
  txSlot* instance;
160
225k
  if (!mxHasTarget) {
161
19.5k
    char buffer[256];
162
19.5k
    txString p = buffer;
163
19.5k
    txDateTime dt;
164
19.5k
    if (secure)
165
0
      mxTypeError("secure mode");
166
19.5k
    mxResult->value.number = fxDateNow();
167
19.5k
    mxResult->kind = XS_NUMBER_KIND;
168
19.5k
    fxDateSplit(mxResult->value.number, 0, &dt);
169
19.5k
    p = fxDatePrintDay(p, dt.day);
170
19.5k
    *p++ = ' ';
171
19.5k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
172
19.5k
    *p++ = ' ';
173
19.5k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
174
19.5k
    *p++ = ' ';
175
19.5k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
176
19.5k
    *p = 0;
177
19.5k
    fxCopyStringC(the, mxResult, buffer);
178
19.5k
    return;
179
19.5k
  }
180
205k
  mxPushSlot(mxTarget);
181
205k
  fxGetPrototypeFromConstructor(the, &mxDatePrototype);
182
205k
  instance = fxNewDateInstance(the);
183
205k
  mxPullSlot(mxResult);
184
205k
  if (c > 1) {
185
27.3k
    dt.year = fxDateFullYear(the, mxArgv(0));
186
27.3k
    dt.month = fxToNumber(the, mxArgv(1));
187
27.3k
    dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
188
27.3k
    dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
189
27.3k
    dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
190
27.3k
    dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
191
27.3k
    dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
192
27.3k
    instance->next->value.number = fxDateMerge(&dt, 0);
193
27.3k
    return;
194
27.3k
  }
195
178k
  if (c > 0) {
196
174k
    txSlot* slot = mxArgv(0);
197
174k
    if (slot->kind == XS_REFERENCE_KIND) {
198
1.70k
      txSlot* date = slot->value.reference;
199
1.70k
      if ((date->next) && (date->next->kind == XS_DATE_KIND)) {
200
1.08k
        instance->next->value.number = date->next->value.number;
201
1.08k
        return;
202
1.08k
      }
203
1.70k
    }
204
173k
    fxToPrimitive(the, slot, XS_NO_HINT);
205
173k
    if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
206
14.5k
      mxPushSlot(mxFunction);
207
14.5k
      mxDub();
208
14.5k
      mxGetID(mxID(_parse));
209
14.5k
      mxCall();
210
14.5k
      mxPushSlot(slot);
211
14.5k
      mxRunCount(1);
212
14.5k
      instance->next->value.number = the->stack->value.number;
213
14.5k
      mxPop();
214
14.5k
      return;
215
14.5k
    }
216
158k
    instance->next->value.number = fxDateClip(fxToNumber(the, slot));
217
158k
    return;
218
173k
  }
219
4.01k
  if (secure)
220
0
    mxTypeError("secure mode");
221
4.01k
  instance->next->value.number = fxDateNow();
222
4.01k
}
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
615k
{
242
615k
  txByte c = *theCharacter;
243
615k
  txString p = *theString;
244
615k
  txInteger aResult = c - '0';
245
615k
  c = c_read8(p++);
246
1.16M
  while (('0' <= c) && (c <= '9')) {
247
553k
#if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_mul_overflow)
248
553k
    if (__builtin_mul_overflow(aResult, 10, &aResult) ||
249
546k
      __builtin_add_overflow(aResult, c - '0', &aResult))
250
15.0k
      *overflow = 1;
251
#else
252
    aResult = (aResult * 10) + c - '0';
253
    if (aResult < 0)
254
      *overflow = 1;
255
#endif
256
553k
    c = c_read8(p++);
257
553k
  }
258
615k
  *theCharacter = c;
259
615k
  *theString = p;
260
615k
  return aResult;
261
615k
}
262
263
txInteger fx_Date_parse_fraction(txByte* theCharacter, txString* theString)
264
1.95k
{
265
1.95k
  txByte c = *theCharacter;
266
1.95k
  txString p = *theString;
267
1.95k
  txNumber fraction = 100;
268
1.95k
  txNumber aResult = ((c - '0') * fraction);
269
1.95k
  c = c_read8(p++);
270
4.35k
  while (('0' <= c) && (c <= '9')) {
271
2.40k
    fraction /= 10;
272
2.40k
    aResult = aResult + ((c - '0') * fraction);
273
2.40k
    c = c_read8(p++);
274
2.40k
  }
275
1.95k
  *theCharacter = c;
276
1.95k
  *theString = p;
277
1.95k
  return (txInteger)c_trunc(aResult);
278
1.95k
}
279
280
void fx_Date_parse(txMachine* the)
281
763k
{
282
3.95M
  #define mxDayCount 7
283
763k
  static const char* const gxDays[mxDayCount] ICACHE_RODATA_ATTR = {
284
763k
    "monday", 
285
763k
    "tuesday", 
286
763k
    "wednesday", 
287
763k
    "thursday", 
288
763k
    "friday",
289
763k
    "saturday", 
290
763k
    "sunday"
291
763k
  };
292
5.97M
  #define mxMonthCount 12
293
763k
  static const char* const gxMonths[mxMonthCount] ICACHE_RODATA_ATTR = {
294
763k
    "january",
295
763k
    "february",
296
763k
    "march",
297
763k
    "april",
298
763k
    "may",
299
763k
    "june",
300
763k
    "july",
301
763k
    "august",
302
763k
    "september",
303
763k
    "october",
304
763k
    "november",
305
763k
    "december"
306
763k
  };
307
5.19M
  #define mxZoneCount 11
308
763k
  static const char* const gxZones[mxZoneCount] ICACHE_RODATA_ATTR = {
309
763k
    "gmt", "ut", "utc",
310
763k
    "est", "edt",
311
763k
    "cst", "cdt",
312
763k
    "mst", "mdt",
313
763k
    "pst", "pdt"
314
763k
  };
315
763k
  static const int gxDeltas[mxZoneCount] ICACHE_XS6RO2_ATTR = {
316
763k
    0, 0, 0,
317
763k
    -5, -4,
318
763k
    -6, -5,
319
763k
    -7, -6,
320
763k
    -8, -7
321
763k
  };
322
  
323
763k
  txString aString;
324
763k
  txBoolean overflow = 0;
325
763k
  txDateTime dt;
326
763k
  txString p;
327
763k
  txString q;
328
763k
  txByte c;
329
763k
  char buffer[10];  /* base type should be the same as txString */
330
763k
  txInteger aComment;
331
763k
  txInteger aDelta;
332
763k
  txInteger aValue;
333
763k
  txSize aLength;
334
763k
  txInteger i;
335
763k
  txInteger yearSign = 1;
336
    
337
763k
  if (mxArgc < 1)
338
69
    goto fail;
339
763k
  aString = fxToString(the, mxArgv(0));
340
  
341
763k
  dt.seconds = -1;
342
763k
  dt.minutes = -1;
343
763k
  dt.hours = -1;
344
763k
  dt.date = -1;
345
763k
  dt.month = -1;
346
763k
  dt.year = -1;
347
763k
  dt.milliseconds = -1;
348
763k
  aComment = 0;
349
763k
  aDelta = -1;
350
351
763k
  c = c_read8(aString++);
352
9.49M
  while (c) {
353
9.48M
    if (c == '(') {
354
3.96k
      aComment++;
355
3.96k
      c = c_read8(aString++);
356
3.96k
      continue;
357
3.96k
    }
358
9.47M
    else if (c == ')') {
359
5.77k
      if (aComment) {
360
464
        aComment--;
361
464
        c = c_read8(aString++);
362
464
        continue;
363
464
      }
364
5.30k
      else
365
5.30k
        goto fail;
366
5.77k
    }
367
9.47M
    else if (aComment) {
368
173k
      c = c_read8(aString++);
369
173k
      continue;
370
173k
    }  
371
    
372
9.29M
    if ((c <= ' ') || (c == ',')) {
373
8.17M
      c = c_read8(aString++);
374
8.17M
      continue;
375
8.17M
    }
376
      
377
1.12M
    else if ((c == '-') | (c == '+')) {
378
24.3k
            txInteger aSign;
379
24.3k
      if (c == '-')  
380
20.3k
        aSign = -1;
381
4.00k
      else
382
4.00k
        aSign = 1;
383
24.3k
      c = c_read8(aString++);
384
24.3k
      if (('0' <= c) && (c <= '9')) {
385
22.7k
        aValue = fx_Date_parse_number(&c, &aString, &overflow);
386
22.7k
        if (c == '-') {
387
6.74k
          if (dt.year >= 0)
388
1.28k
            goto fail;
389
5.45k
          dt.year = aValue;
390
5.45k
          yearSign = aSign;
391
5.45k
          c = c_read8(aString++);
392
5.45k
          if (('0' <= c) && (c <= '9')) {
393
3.59k
            dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
394
3.59k
            if (c == '-') {
395
2.04k
              c = c_read8(aString++);
396
2.04k
              if (('0' <= c) && (c <= '9'))
397
1.82k
                dt.date = fx_Date_parse_number(&c, &aString, &overflow);
398
216
              else
399
216
                dt.date = 1;
400
2.04k
            }
401
3.59k
          }
402
1.85k
          else
403
1.85k
            dt.month = 0;
404
5.45k
        }
405
15.9k
        else {
406
15.9k
          if ((aDelta != 0) && (aDelta != -1))
407
584
            goto fail;
408
15.3k
          if (c == ':') {
409
5.33k
            aDelta = 60 * aValue;
410
5.33k
            c = c_read8(aString++);
411
5.33k
            if (('0' <= c) && (c <= '9')) {
412
2.73k
              aDelta += fx_Date_parse_number(&c, &aString, &overflow);
413
2.73k
            }
414
5.33k
          }
415
10.0k
          else {
416
10.0k
            if (aValue < 24)
417
6.55k
              aDelta = aValue * 60;
418
3.51k
            else
419
3.51k
              aDelta = (aValue % 100) + ((aValue / 100) * 60);
420
10.0k
          }
421
15.3k
          aDelta *= aSign;
422
15.3k
        }
423
22.7k
      }
424
1.61k
      else
425
1.61k
        goto fail;
426
24.3k
    }    
427
1.10M
    else if (('0' <= c) && (c <= '9')) {
428
315k
      aValue = fx_Date_parse_number(&c, &aString, &overflow);
429
315k
      if (c == ':') {
430
25.8k
        if (dt.hours >= 0) 
431
354
          goto fail;
432
25.5k
        dt.hours = aValue;  
433
25.5k
        c = c_read8(aString++);
434
25.5k
        if (('0' <= c) && (c <= '9')) {
435
14.0k
          dt.minutes = fx_Date_parse_number(&c, &aString, &overflow);
436
14.0k
          if (c == ':') {
437
11.5k
            c = c_read8(aString++);
438
11.5k
            if (('0' <= c) && (c <= '9')) {
439
8.68k
              dt.seconds = fx_Date_parse_number(&c, &aString, &overflow);
440
8.68k
              if (c == '.') {
441
4.04k
                c = c_read8(aString++);
442
4.04k
                if (('0' <= c) && (c <= '9')) {
443
1.95k
                  dt.milliseconds = fx_Date_parse_fraction(&c, &aString);
444
1.95k
                }
445
4.04k
              }
446
8.68k
            }
447
2.90k
            else
448
2.90k
              dt.seconds = 0;
449
11.5k
          }
450
14.0k
        }
451
11.4k
        else
452
11.4k
          dt.seconds = 0;
453
25.5k
      }
454
290k
      else if (c == '/') {
455
4.69k
        if (dt.year >= 0)
456
263
          goto fail;
457
4.43k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
458
4.43k
        c = c_read8(aString++);
459
4.43k
        if (('0' <= c) && (c <= '9')) {
460
4.11k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
461
4.11k
          if (c == '/') {
462
2.75k
            c = c_read8(aString++);
463
2.75k
            if (('0' <= c) && (c <= '9')) {
464
174
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
465
174
            }
466
2.57k
            else
467
2.57k
              dt.date = 1;
468
2.75k
          }
469
4.11k
        }
470
325
        else
471
325
          dt.month = 0;
472
4.43k
      }
473
285k
      else if (c == '-') {
474
243k
        if (dt.year >= 0)
475
535
          goto fail;
476
242k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
477
242k
        c = c_read8(aString++);
478
242k
        if (('0' <= c) && (c <= '9')) {
479
240k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
480
240k
          if (c == '-') {
481
2.69k
            c = c_read8(aString++);
482
2.69k
            if (('0' <= c) && (c <= '9'))
483
773
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
484
1.91k
            else
485
1.91k
              dt.date = 1;
486
2.69k
          }
487
240k
        }
488
1.77k
        else
489
1.77k
          dt.month = 0;
490
242k
      }
491
42.0k
      else {
492
42.0k
        if (aValue < 70) {
493
22.8k
          if (dt.date < 0)
494
19.5k
            dt.date = aValue;
495
3.31k
          else
496
3.31k
            goto fail;
497
22.8k
        }
498
19.2k
        else {
499
19.2k
          if (dt.year < 0)
500
14.4k
            dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
501
4.76k
          else
502
4.76k
            goto fail;
503
19.2k
        }
504
42.0k
      }
505
315k
    }        
506
785k
    else if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'))) {
507
528k
      txSize cmpLength;
508
528k
      p = buffer;
509
528k
      q = p + sizeof(buffer) - 1;
510
2.06M
      do {
511
2.06M
        if (p == q) goto fail;
512
1.98M
        *p++ = (c >= 'a') ? c : (c + ('a' - 'A'));
513
1.98M
        c = c_read8(aString++);
514
1.98M
      } while ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')));
515
454k
      *p = 0;
516
454k
      aLength = mxPtrDiff(p - (txString)buffer);
517
454k
      cmpLength = (aLength >= 3) ? aLength : 3;
518
454k
      if (c_strcmp("am", buffer) == 0) {
519
6.16k
        if ((dt.hours < 0) || (12 <  dt.hours))
520
2.30k
          goto fail;
521
3.86k
        if (dt.hours == 12)
522
1.24k
          dt.hours = 0;
523
3.86k
        continue;
524
6.16k
      }
525
448k
      if (c_strcmp("pm", buffer) == 0) {
526
5.42k
        if ((dt.hours < 0) || (12 <  dt.hours))
527
2.88k
          goto fail;
528
2.53k
        if (dt.hours != 12)
529
1.00k
          dt.hours += 12;
530
2.53k
        continue;
531
5.42k
      }
532
3.50M
      for (i = 0; i < mxDayCount; i++)
533
3.07M
        if (c_strncmp(gxDays[i], buffer, cmpLength) == 0)
534
9.57k
          break;
535
443k
      if (i < mxDayCount)
536
9.57k
        continue;
537
5.53M
      for (i = 0; i < mxMonthCount; i++)
538
5.13M
        if (c_strncmp(gxMonths[i], buffer, cmpLength) == 0)
539
30.9k
          break;
540
433k
      if (i < mxMonthCount) {
541
30.9k
        if (dt.month < 0) {
542
30.4k
          dt.month = i;
543
30.4k
          continue;
544
30.4k
        }
545
519
        else
546
519
          goto fail;
547
30.9k
      }
548
4.79M
      for (i = 0; i < mxZoneCount; i++)
549
4.39M
        if (c_strcmp(gxZones[i], buffer) == 0)
550
3.53k
          break;
551
402k
      if (i < mxZoneCount) {
552
3.53k
        if (aDelta == -1) {
553
263
          aDelta = gxDeltas[i] * 60;
554
263
          continue;
555
263
        }
556
3.27k
        else
557
3.27k
          goto fail;
558
3.53k
      }
559
399k
      if (c_strcmp("t", buffer) == 0) {
560
2.16k
        if (dt.year < 0) 
561
319
          goto fail;
562
1.84k
        continue;
563
2.16k
      }
564
397k
      if (c_strcmp("z", buffer) == 0) {
565
7.32k
        if (dt.hours < 0) 
566
2.68k
          goto fail;
567
4.63k
        aDelta = 0;
568
4.63k
        continue;
569
7.32k
      }
570
389k
      goto fail;
571
397k
    }
572
256k
    else
573
256k
      goto fail;
574
9.29M
  }
575
13.0k
   if (overflow)
576
391
       goto fail;
577
12.6k
   if (dt.year < 0)
578
7.44k
       goto fail;
579
5.21k
  if ((yearSign < 0) && (dt.year == 0))
580
115
       goto fail;
581
5.09k
  if (dt.month < 0)
582
2.93k
    dt.month = 0;
583
5.09k
  if (dt.date < 0)
584
3.43k
    dt.date = 1;
585
5.09k
  if ((aDelta < 0) && (dt.hours < 0) && (dt.minutes < 0) && (dt.seconds < 0) && (dt.milliseconds < 0))
586
1.56k
    aDelta = 0;
587
5.09k
  if (dt.hours < 0)
588
1.57k
    dt.hours = 0;
589
5.09k
  if (dt.minutes < 0)
590
3.04k
    dt.minutes = 0;
591
5.09k
    if (dt.seconds < 0)
592
2.31k
        dt.seconds = 0;
593
5.09k
    if (dt.milliseconds < 0)
594
3.80k
        dt.milliseconds = 0;
595
5.09k
    dt.year *= yearSign;
596
5.09k
  mxResult->value.number = fxDateMerge(&dt, (aDelta != -1) ? 1 : 0);
597
5.09k
  if (aDelta != -1)
598
2.87k
    mxResult->value.number -= (txNumber)aDelta * 60000.0;
599
5.09k
  mxResult->kind = XS_NUMBER_KIND;
600
5.09k
  return;
601
758k
fail:
602
758k
  mxResult->value.number = C_NAN;
603
758k
  mxResult->kind = XS_NUMBER_KIND;
604
  //mxSyntaxError("invalid parameter");
605
758k
}
606
607
void fx_Date_UTC(txMachine* the)
608
212k
{
609
212k
  txInteger c = mxArgc;
610
212k
  txDateTime dt;
611
212k
  dt.year = (c > 0) ? fxDateFullYear(the, mxArgv(0)) : C_NAN;
612
212k
  dt.month = (c > 1) ? fxToNumber(the, mxArgv(1)) : 0;
613
212k
  dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
614
212k
  dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
615
212k
  dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
616
212k
  dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
617
212k
  dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
618
212k
  mxResult->value.number = fxDateMerge(&dt, 1);
619
212k
    mxResult->kind = XS_NUMBER_KIND;
620
212k
}
621
622
txBoolean fx_Date_prototype_get_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
623
191k
{
624
191k
  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
191k
  number = slot->value.number;
636
191k
  if (c_isnan(number)) {
637
163k
    mxResult->value.number = C_NAN;
638
163k
    mxResult->kind = XS_NUMBER_KIND;
639
163k
    dt->value = C_NAN;
640
163k
    return 0;
641
163k
  }
642
28.1k
  fxDateSplit(slot->value.number, utc, dt);
643
28.1k
  return 1;
644
191k
}
645
646
void fx_Date_prototype_set_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
647
509
{
648
509
  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
509
  if (c_isnan(number))
661
209
    return;
662
300
  if (slot->flag & XS_DONT_SET_FLAG)
663
0
    mxTypeError("this: read-only Date instance");
664
300
  mxResult->value.number = slot->value.number = fxDateMerge(dt, utc);
665
300
  mxResult->kind = XS_NUMBER_KIND;
666
300
}
667
668
void fx_Date_prototype_getMilliseconds(txMachine* the)
669
63
{
670
63
  txDateTime dt;
671
63
  txSlot* slot = fxDateCheck(the);
672
63
  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
63
}
677
678
void fx_Date_prototype_getSeconds(txMachine* the)
679
39
{
680
39
  txDateTime dt;
681
39
  txSlot* slot = fxDateCheck(the);
682
39
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
683
21
    mxResult->value.integer = (txInteger)dt.seconds;
684
21
    mxResult->kind = XS_INTEGER_KIND;
685
21
  }
686
39
}
687
688
void fx_Date_prototype_getMinutes(txMachine* the)
689
38
{
690
38
  txDateTime dt;
691
38
  txSlot* slot = fxDateCheck(the);
692
38
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
693
20
    mxResult->value.integer = (txInteger)dt.minutes;
694
20
    mxResult->kind = XS_INTEGER_KIND;
695
20
  }
696
38
}
697
698
void fx_Date_prototype_getHours(txMachine* the)
699
37
{
700
37
  txDateTime dt;
701
37
  txSlot* slot = fxDateCheck(the);
702
37
  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
37
}
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
18
    mxResult->value.integer = dt.day;
714
18
    mxResult->kind = XS_INTEGER_KIND;
715
18
  }
716
76.0k
}
717
718
void fx_Date_prototype_getDate(txMachine* the)
719
112k
{
720
112k
  txDateTime dt;
721
112k
  txSlot* slot = fxDateCheck(the);
722
112k
  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
112k
}
727
728
void fx_Date_prototype_getMonth(txMachine* the)
729
36
{
730
36
  txDateTime dt;
731
36
  txSlot* slot = fxDateCheck(the);
732
36
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
733
20
    mxResult->value.integer = (txInteger)dt.month;
734
20
    mxResult->kind = XS_INTEGER_KIND;
735
20
  }
736
36
}
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
51
{
750
51
  txDateTime dt;
751
51
  txSlot* slot = fxDateCheck(the);
752
51
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
753
13
    mxResult->value.integer = (txInteger)dt.year;
754
13
    mxResult->kind = XS_INTEGER_KIND;
755
13
  }
756
51
}
757
758
void fx_Date_prototype_getUTCMilliseconds(txMachine* the)
759
51
{
760
51
  txDateTime dt;
761
51
  txSlot* slot = fxDateCheck(the);
762
51
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
763
11
    mxResult->value.integer = (txInteger)dt.milliseconds;
764
11
    mxResult->kind = XS_INTEGER_KIND;
765
11
  }
766
51
}
767
768
void fx_Date_prototype_getUTCSeconds(txMachine* the)
769
516
{
770
516
  txDateTime dt;
771
516
  txSlot* slot = fxDateCheck(the);
772
516
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
773
18
    mxResult->value.integer = (txInteger)dt.seconds;
774
18
    mxResult->kind = XS_INTEGER_KIND;
775
18
  }
776
516
}
777
778
void fx_Date_prototype_getUTCMinutes(txMachine* the)
779
67
{
780
67
  txDateTime dt;
781
67
  txSlot* slot = fxDateCheck(the);
782
67
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
783
21
    mxResult->value.integer = (txInteger)dt.minutes;
784
21
    mxResult->kind = XS_INTEGER_KIND;
785
21
  }
786
67
}
787
788
void fx_Date_prototype_getUTCHours(txMachine* the)
789
38
{
790
38
  txDateTime dt;
791
38
  txSlot* slot = fxDateCheck(the);
792
38
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
793
18
    mxResult->value.integer = (txInteger)dt.hours;
794
18
    mxResult->kind = XS_INTEGER_KIND;
795
18
  }
796
38
}
797
798
void fx_Date_prototype_getUTCDay(txMachine* the)
799
81
{
800
81
  txDateTime dt;
801
81
  txSlot* slot = fxDateCheck(the);
802
81
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
803
36
    mxResult->value.integer = dt.day;
804
36
    mxResult->kind = XS_INTEGER_KIND;
805
36
  }
806
81
}
807
808
void fx_Date_prototype_getUTCDate(txMachine* the)
809
48
{
810
48
  txDateTime dt;
811
48
  txSlot* slot = fxDateCheck(the);
812
48
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
813
24
    mxResult->value.integer = (txInteger)dt.date;
814
24
    mxResult->kind = XS_INTEGER_KIND;
815
24
  }
816
48
}
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
46
{
830
46
  txDateTime dt;
831
46
  txSlot* slot = fxDateCheck(the);
832
46
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
833
11
    mxResult->value.integer = (txInteger)dt.year;
834
11
    mxResult->kind = XS_INTEGER_KIND;
835
11
  }
836
46
}
837
838
void fx_Date_prototype_getTimezoneOffset(txMachine* the)
839
43
{
840
43
  txDateTime dt;
841
43
  txSlot* slot = fxDateCheck(the);
842
43
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
843
17
    mxResult->value.integer = 0 - dt.offset;
844
17
    mxResult->kind = XS_INTEGER_KIND;
845
17
  }
846
43
}
847
848
void fx_Date_prototype_setMilliseconds(txMachine* the)
849
82
{
850
82
  txInteger c = mxArgc;
851
82
  txDateTime dt;
852
82
  txSlot* slot = fxDateCheck(the);
853
82
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
854
82
  dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
855
82
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
856
82
}
857
858
void fx_Date_prototype_setSeconds(txMachine* the)
859
58
{
860
58
  txInteger c = mxArgc;
861
58
  txDateTime dt;
862
58
  txSlot* slot = fxDateCheck(the);
863
58
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
864
58
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
865
58
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
866
58
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
867
58
}
868
869
void fx_Date_prototype_setMinutes(txMachine* the)
870
1.88k
{
871
1.88k
  txInteger c = mxArgc;
872
1.88k
  txDateTime dt;
873
1.88k
  txSlot* slot = fxDateCheck(the);
874
1.88k
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
875
1.88k
  dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
876
1.88k
  if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1));
877
1.88k
  if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2));
878
1.88k
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
879
1.88k
}
880
881
void fx_Date_prototype_setHours(txMachine* the)
882
73
{
883
73
  txInteger c = mxArgc;
884
73
  txDateTime dt;
885
73
  txSlot* slot = fxDateCheck(the);
886
73
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
887
73
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
888
73
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
889
73
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
890
73
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
891
73
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
892
73
}
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
357
{
906
357
  txInteger c = mxArgc;
907
357
  txDateTime dt;
908
357
  txSlot* slot = fxDateCheck(the);
909
357
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
910
357
  dt.month = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
911
357
  if (c > 1) dt.date = fxToNumber(the, mxArgv(1));
912
357
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
913
357
}
914
915
void fx_Date_prototype_setYear(txMachine* the)
916
1
{
917
1
  txInteger c = mxArgc;
918
1
  txDateTime dt;
919
1
  txSlot* slot = fxDateCheck(the);
920
1
  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
1
  else
925
1
    fx_Date_prototype_get_aux(the, &dt, 0, slot);
926
1
  dt.year = (mxArgc > 0) ? fxDateFullYear(the, mxArgv(0)) : C_NAN;
927
1
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
928
1
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
929
1
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
930
1
}
931
932
void fx_Date_prototype_setFullYear(txMachine* the)
933
70
{
934
70
  txInteger c = mxArgc;
935
70
  txDateTime dt;
936
70
  txSlot* slot = fxDateCheck(the);
937
70
  if (c_isnan(slot->value.number)) {
938
4
    slot->value.number = 0;
939
4
    fx_Date_prototype_get_aux(the, &dt, 1, slot);
940
4
  }
941
66
  else
942
66
    fx_Date_prototype_get_aux(the, &dt, 0, slot);
943
70
  dt.year = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
944
70
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
945
70
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
946
70
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
947
70
}
948
949
void fx_Date_prototype_setTime(txMachine* the)
950
76
{
951
76
  txSlot* slot = fxDateCheck(the);
952
76
  if (slot->flag & XS_DONT_SET_FLAG)
953
0
    mxTypeError("this: read-only Date instance");
954
76
  if (mxArgc < 1)
955
3
    slot->value.number = C_NAN;
956
73
  else {
957
73
    txNumber number = fxToNumber(the, mxArgv(0));
958
73
    int fpclass = c_fpclassify(number);
959
73
    if (fpclass != C_FP_NAN) {
960
35
      if (c_fabs(number) > 8.64e15)
961
1
        number = C_NAN;
962
34
      else
963
34
        number = c_trunc(number);
964
35
    }
965
73
    slot->value.number = number;
966
73
  }
967
76
  mxResult->value.number = slot->value.number;
968
76
  mxResult->kind = XS_NUMBER_KIND;
969
76
}
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
1.82k
{
983
1.82k
  txInteger c = mxArgc;
984
1.82k
  txDateTime dt;
985
1.82k
  txSlot* slot = fxDateCheck(the);
986
1.82k
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
987
1.82k
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
988
1.82k
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
989
1.82k
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
990
1.82k
}
991
992
void fx_Date_prototype_setUTCMinutes(txMachine* the)
993
42
{
994
42
  txInteger c = mxArgc;
995
42
  txDateTime dt;
996
42
  txSlot* slot = fxDateCheck(the);
997
42
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
998
42
  dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
999
42
  if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1));
1000
42
  if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2));
1001
42
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1002
42
}
1003
1004
void fx_Date_prototype_setUTCHours(txMachine* the)
1005
18
{
1006
18
  txInteger c = mxArgc;
1007
18
  txDateTime dt;
1008
18
  txSlot* slot = fxDateCheck(the);
1009
18
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1010
18
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1011
18
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
1012
18
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
1013
18
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
1014
18
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1015
18
}
1016
1017
void fx_Date_prototype_setUTCDate(txMachine* the)
1018
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.92k
{
1029
1.92k
  txInteger c = mxArgc;
1030
1.92k
  txDateTime dt;
1031
1.92k
  txSlot* slot = fxDateCheck(the);
1032
1.92k
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1033
1.92k
  dt.month = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1034
1.92k
  if (c > 1) dt.date = fxToNumber(the, mxArgv(1));
1035
1.92k
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1036
1.92k
}
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.05k
{
1053
2.05k
  char buffer[256];
1054
2.05k
  txDateTime dt;
1055
2.05k
  txSlot* slot = fxDateCheck(the);
1056
2.05k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1057
1.46k
    txString p = buffer;
1058
1.46k
    p = fxDatePrintDay(p, dt.day);
1059
1.46k
    *p++ = ' ';
1060
1.46k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1061
1.46k
    *p = 0;
1062
1.46k
  }
1063
592
  else
1064
592
    c_strcpy(buffer, "Invalid Date");
1065
2.05k
  fxCopyStringC(the, mxResult, buffer);
1066
2.05k
}
1067
1068
void fx_Date_prototype_toISOString(txMachine* the)
1069
36
{
1070
36
  char buffer[256];
1071
36
  txDateTime dt;
1072
36
  txSlot* slot = fxDateCheck(the);
1073
36
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
1074
31
    txString p = buffer;
1075
31
    p = fxDatePrintYear(p, (txInteger)dt.year);
1076
31
    *p++ = '-';
1077
31
    p = fxDatePrint2Digits(p, (txInteger)dt.month + 1);
1078
31
    *p++ = '-';
1079
31
    p = fxDatePrint2Digits(p, (txInteger)dt.date);
1080
31
    *p++ = 'T';
1081
31
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1082
31
    *p++ = '.';
1083
31
    p = fxDatePrint3Digits(p, (txInteger)dt.milliseconds);
1084
31
    *p++ = 'Z';
1085
31
    *p = 0;
1086
31
  }
1087
5
  else
1088
5
        mxRangeError("Invalid Date");
1089
31
  fxCopyStringC(the, mxResult, buffer);
1090
31
}
1091
1092
void fx_Date_prototype_toJSON(txMachine* the)
1093
20
{
1094
20
  fxToInstance(the, mxThis);
1095
20
  mxPushSlot(mxThis);
1096
20
  fxToPrimitive(the, the->stack, XS_NUMBER_HINT);
1097
20
  if ((the->stack->kind == XS_NUMBER_KIND) && !c_isfinite(the->stack->value.number)) {
1098
6
    mxPop();
1099
6
    mxResult->kind = XS_NULL_KIND;
1100
6
  }
1101
14
  else {   
1102
14
    mxPop();
1103
14
    mxPushSlot(mxThis);
1104
14
    mxDub();
1105
14
    mxGetID(mxID(_toISOString));
1106
14
    mxCall();
1107
14
    mxRunCount(0);
1108
14
    mxPullSlot(mxResult);
1109
14
  }
1110
20
}
1111
1112
void fx_Date_prototype_toPrimitive(txMachine* the)
1113
40.7k
{
1114
40.7k
  if (mxIsReference(mxThis)) {
1115
40.6k
    txInteger hint = XS_NO_HINT;
1116
40.6k
    txInteger ids[2], i;
1117
40.6k
    if (mxArgc > 0) {
1118
40.6k
      txSlot* slot = mxArgv(0);
1119
40.6k
      if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
1120
40.6k
        if (!c_strcmp(slot->value.string, "default"))
1121
21.4k
          hint = XS_STRING_HINT;
1122
19.2k
        else if (!c_strcmp(slot->value.string, "number"))
1123
17.5k
          hint = XS_NUMBER_HINT;
1124
1.76k
        else if (!c_strcmp(slot->value.string, "string"))
1125
1.75k
          hint = XS_STRING_HINT;
1126
40.6k
      }
1127
40.6k
    }
1128
40.6k
    if (hint == XS_STRING_HINT) {
1129
23.1k
      ids[0] = mxID(_toString);
1130
23.1k
      ids[1] = mxID(_valueOf);
1131
23.1k
    }
1132
17.5k
    else if (hint == XS_NUMBER_HINT) {
1133
17.5k
      ids[0] = mxID(_valueOf);
1134
17.5k
      ids[1] = mxID(_toString);
1135
17.5k
    }
1136
25
    else
1137
25
        mxTypeError("invalid hint");
1138
40.6k
    for (i = 0; i < 2; i++) {
1139
40.6k
      mxPushSlot(mxThis);
1140
40.6k
      mxPushSlot(mxThis);
1141
40.6k
      mxGetID(ids[i]);
1142
40.6k
      if (fxIsCallable(the, the->stack)) {
1143
40.6k
        mxCall();
1144
40.6k
        mxRunCount(0);
1145
40.6k
        if (mxIsReference(the->stack))
1146
3
          mxPop();
1147
40.6k
        else {
1148
40.6k
          mxPullSlot(mxResult);
1149
40.6k
          return;
1150
40.6k
            }
1151
40.6k
      }
1152
5
      else {
1153
5
        mxPop();
1154
5
        mxPop();
1155
5
      }
1156
40.6k
    }
1157
3
    if (hint == XS_STRING_HINT)
1158
2
            mxTypeError("cannot coerce object to string");
1159
1
        else
1160
1
            mxTypeError("cannot coerce object to number");
1161
3
  }
1162
11
  else {
1163
11
        mxTypeError("invalid this");
1164
11
  }
1165
40.7k
}
1166
1167
void fx_Date_prototype_toString(txMachine* the)
1168
23.1k
{
1169
23.1k
  char buffer[256];
1170
23.1k
  txDateTime dt;
1171
23.1k
  txSlot* slot = fxDateCheck(the);
1172
23.1k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1173
19.7k
    txString p = buffer;
1174
19.7k
    p = fxDatePrintDay(p, dt.day);
1175
19.7k
    *p++ = ' ';
1176
19.7k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1177
19.7k
    *p++ = ' ';
1178
19.7k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1179
19.7k
    *p++ = ' ';
1180
19.7k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
1181
19.7k
    *p = 0;
1182
19.7k
  }
1183
3.43k
  else
1184
3.43k
    c_strcpy(buffer, "Invalid Date");
1185
23.1k
  fxCopyStringC(the, mxResult, buffer);
1186
23.1k
}
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.70k
{
1207
1.70k
  char buffer[256];
1208
1.70k
  txDateTime dt;
1209
1.70k
  txSlot* slot = fxDateCheck(the);
1210
1.70k
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
1211
890
    txString p = buffer;
1212
890
    p = fxDatePrintDay(p, dt.day);
1213
890
    *p++ = ',';
1214
890
    *p++ = ' ';
1215
890
    p = fxDatePrintDateUTC(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1216
890
    *p++ = ' ';
1217
890
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1218
890
    *p++ = ' ';
1219
890
    *p++ = 'G';
1220
890
    *p++ = 'M';
1221
890
    *p++ = 'T';
1222
890
    *p = 0;
1223
890
  }
1224
812
  else
1225
812
    c_strcpy(buffer, "Invalid Date");
1226
1.70k
  fxCopyStringC(the, mxResult, buffer);
1227
1.70k
}
1228
1229
void fx_Date_prototype_valueOf(txMachine* the)
1230
17.8k
{
1231
17.8k
  txSlot* slot = fxDateCheck(the);
1232
17.8k
  mxResult->kind = XS_NUMBER_KIND;
1233
17.8k
  mxResult->value = slot->value;
1234
17.8k
}
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
598k
#define mx1YearDays 365
1259
448k
#define mx4YearsDays ((4 * mx1YearDays) + 1)
1260
299k
#define mx100YearsDays ((25 * mx4YearsDays) - 1)
1261
149k
#define mx400YearsDays ((4 * mx100YearsDays) + 1)
1262
480k
#define mxDayMilliseconds 86400000.0
1263
#define mxYearDays(YEAR) \
1264
487k
  ((365 * (YEAR)) + ((YEAR) / 4) - ((YEAR) / 100) + ((YEAR) / 400) + 1)
1265
#define mxIsLeapYear(YEAR) \
1266
117k
  (((YEAR) % 4) ? 0 : ((YEAR) % 100) ? 1 : ((YEAR) % 400) ? 0 : 1)
1267
444k
#define mxYearsOffset 400000
1268
1269
txSlot* fxDateCheck(txMachine* the)
1270
243k
{
1271
243k
  txSlot* it = mxThis;
1272
243k
  if (it->kind == XS_REFERENCE_KIND) {
1273
210k
    txSlot* instance = it->value.reference;
1274
210k
    it = instance->next;
1275
210k
    if ((it) && (it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_DATE_KIND))
1276
209k
      return it;
1277
210k
  }
1278
243k
  mxTypeError("this: not a Date instance");
1279
0
  return C_NULL;
1280
243k
}
1281
1282
txNumber fxDateClip(txNumber value)
1283
679k
{
1284
679k
  if (!c_isfinite(value))
1285
156k
    value = C_NAN;
1286
523k
  else if (c_fabs(value) > 8.64e15)
1287
6.50k
    value = C_NAN;
1288
516k
  else {
1289
516k
    value = c_trunc(value);
1290
516k
    if (value == 0)
1291
759
      value = 0;
1292
516k
  }
1293
679k
  return value; 
1294
679k
}
1295
1296
txNumber fxDateFullYear(txMachine* the, txSlot* slot)
1297
239k
{
1298
239k
  txNumber result = fxToNumber(the, slot);
1299
239k
  if (c_isfinite(result)) {
1300
237k
    txInteger value = fxToInteger(the, slot);
1301
237k
    if ((0 <= value) && (value <= 99))
1302
227k
      result = 1900 + value;
1303
237k
  }
1304
239k
  return result;
1305
239k
}
1306
1307
txNumber fxDateMerge(txDateTime* dt, txBoolean utc)
1308
332k
{
1309
332k
  txNumber year, month;
1310
332k
  txInteger monthIndex;
1311
332k
  txBoolean leap;
1312
332k
  txNumber value;
1313
332k
  if ((!c_isfinite(dt->year))
1314
330k
  || (!c_isfinite(dt->month))
1315
330k
  || (!c_isfinite(dt->date))
1316
329k
  || (!c_isfinite(dt->hours))
1317
328k
  || (!c_isfinite(dt->minutes))
1318
328k
  || (!c_isfinite(dt->seconds))
1319
328k
  || (!c_isfinite(dt->milliseconds)))
1320
5.92k
    return C_NAN;
1321
327k
  year = c_trunc(dt->year);
1322
327k
  month = c_trunc(dt->month);
1323
327k
  year += c_floor(month / 12);
1324
327k
  monthIndex = (txInteger)c_fmod(month, 12.0);
1325
327k
  if (monthIndex < 0)
1326
730
    monthIndex += 12;
1327
327k
  leap = (c_fmod(year, 4) == 0) && ((c_fmod(year, 100) != 0) || (c_fmod(year, 400) == 0));
1328
327k
  year += mxYearsOffset - 1;
1329
327k
  value = (365 * year) + c_floor(year / 4) - c_floor(year / 100) + c_floor(year / 400) + 1;
1330
327k
  value -= (txNumber)mxYearDays(1970 + mxYearsOffset - 1);
1331
327k
  if (leap)
1332
24.0k
    value += gxLeapYearMonthsDays[monthIndex];
1333
302k
  else
1334
302k
    value += gxCommonYearMonthsDays[monthIndex];
1335
327k
  value += c_trunc(dt->date) - 1;
1336
327k
  value *= mxDayMilliseconds;
1337
327k
  value += c_trunc(dt->hours) * 60 * 60 * 1000;
1338
327k
  value += c_trunc(dt->minutes) * 60 * 1000;
1339
327k
  value += c_trunc(dt->seconds) * 1000;
1340
327k
    value += c_trunc(dt->milliseconds);
1341
327k
  if (!utc) {
1342
26.9k
    txNumber former = value;
1343
26.9k
    txInteger similar;
1344
26.9k
    c_tm tm;
1345
26.9k
    c_time_t time;
1346
26.9k
    fxDateSplit(value, 1, dt);
1347
26.9k
    similar = fxDateSimilarYear((txInteger)dt->year);
1348
26.9k
    c_memset(&tm, 0, sizeof(c_tm));
1349
26.9k
    tm.tm_year = similar - 1900;
1350
26.9k
    tm.tm_mon = (txInteger)dt->month;
1351
26.9k
    tm.tm_mday = (txInteger)dt->date;
1352
26.9k
    tm.tm_hour = (txInteger)dt->hours;
1353
26.9k
    tm.tm_min = (txInteger)dt->minutes;
1354
26.9k
    tm.tm_sec = (txInteger)dt->seconds;
1355
26.9k
    tm.tm_isdst =-1;
1356
26.9k
    time = c_mktime(&tm);  
1357
26.9k
    if (time == -1)
1358
0
      value = NAN;
1359
26.9k
    else {
1360
26.9k
      value = (txNumber)time;
1361
26.9k
      value *= 1000;
1362
26.9k
      value += dt->milliseconds;
1363
26.9k
      if (similar != year) {
1364
26.9k
        dt->year = similar;
1365
26.9k
        value += former - fxDateMerge(dt, 1);
1366
26.9k
      }
1367
26.9k
    }
1368
26.9k
  }
1369
327k
  return fxDateClip(value);
1370
332k
}
1371
1372
txNumber fxDateNow()
1373
194k
{
1374
194k
  c_timeval tv;
1375
194k
  c_gettimeofday(&tv, NULL);
1376
194k
  return fxDateClip(((txNumber)(tv.tv_sec) * 1000.0) + ((txNumber)(tv.tv_usec / 1000)));
1377
194k
}
1378
1379
txString fxDatePrint2Digits(txString p, txInteger value)
1380
282k
{
1381
282k
  *p++ = '0' + value / 10;
1382
282k
  *p++ = '0' + value % 10;
1383
282k
  return p;
1384
282k
}
1385
1386
txString fxDatePrint3Digits(txString p, txInteger value)
1387
41.7k
{
1388
41.7k
  *p++ = '0' + value / 100;
1389
41.7k
  return fxDatePrint2Digits(p, value % 100);
1390
41.7k
}
1391
1392
txString fxDatePrint4Digits(txString p, txInteger value)
1393
41.7k
{
1394
41.7k
  *p++ = '0' + value / 1000;
1395
41.7k
  return fxDatePrint3Digits(p, value % 1000);
1396
41.7k
}
1397
1398
txString fxDatePrintDate(txString p, txInteger year, txInteger month, txInteger date)
1399
40.7k
{
1400
40.7k
  c_strcpy(p, gxMonthNames[month]);
1401
40.7k
  p += 3;
1402
40.7k
  *p++ = ' ';
1403
40.7k
  p = fxDatePrint2Digits(p, date);
1404
40.7k
  *p++ = ' ';
1405
40.7k
  p = fxDatePrintYear(p, year);
1406
40.7k
  return p;
1407
40.7k
}
1408
1409
txString fxDatePrintDateUTC(txString p, txInteger year, txInteger month, txInteger date)
1410
890
{
1411
890
  p = fxDatePrint2Digits(p, date);
1412
890
  *p++ = ' ';
1413
890
  c_strcpy(p, gxMonthNames[month]);
1414
890
  p += 3;
1415
890
  *p++ = ' ';
1416
890
  p = fxDatePrintYear(p, year);
1417
890
  return p;
1418
890
}
1419
1420
txString fxDatePrintDay(txString p, txInteger day)
1421
41.6k
{
1422
41.6k
  c_strcpy(p, gxDayNames[day]);
1423
41.6k
  p += 3;
1424
41.6k
  return p;
1425
41.6k
}
1426
1427
txString fxDatePrintTime(txString p, txInteger hours, txInteger minutes, txInteger seconds)
1428
40.2k
{
1429
40.2k
  p = fxDatePrint2Digits(p, hours);
1430
40.2k
  *p++ = ':';
1431
40.2k
  p = fxDatePrint2Digits(p, minutes);
1432
40.2k
  *p++ = ':';
1433
40.2k
  p = fxDatePrint2Digits(p, seconds);
1434
40.2k
  return p;
1435
40.2k
}
1436
1437
txString fxDatePrintTimezone(txString p, txInteger offset)
1438
39.3k
{
1439
39.3k
  *p++ = 'G';
1440
39.3k
  *p++ = 'M';
1441
39.3k
  *p++ = 'T';
1442
39.3k
  if (offset < 0) {
1443
0
    offset = 0 - offset;
1444
0
    *p++ = '-';
1445
0
  }
1446
39.3k
  else
1447
39.3k
    *p++ = '+';
1448
39.3k
  p = fxDatePrint2Digits(p, offset / 60);
1449
39.3k
  p = fxDatePrint2Digits(p, offset % 60);
1450
39.3k
  return p;
1451
39.3k
}
1452
1453
txString fxDatePrintYear(txString p, txInteger value)
1454
41.7k
{
1455
41.7k
  if ((value < 0) || (9999 < value)) {
1456
4.27k
    if (value < 0) {
1457
1.90k
      *p++ = '-';
1458
1.90k
      value = -value;
1459
1.90k
    }
1460
2.36k
    else
1461
2.36k
      *p++ = '+';
1462
4.27k
    if (99999 < value) {
1463
1.64k
      *p++ = '0' + value / 100000;
1464
1.64k
      value %= 100000;
1465
1.64k
    }
1466
4.27k
    if (9999 < value) {
1467
3.14k
      *p++ = '0' + value / 10000;
1468
3.14k
      value %= 10000;
1469
3.14k
    }
1470
4.27k
  }
1471
41.7k
  return fxDatePrint4Digits(p, value);
1472
41.7k
}
1473
1474
txInteger fxDateSimilarYear(txInteger year)
1475
69.9k
{
1476
69.9k
  txInteger leap, day;
1477
69.9k
  if ((1970 <= year) && (year < 2038))
1478
27.2k
    return year;
1479
42.7k
  leap = mxIsLeapYear(year);
1480
42.7k
  year += mxYearsOffset - 1;
1481
42.7k
  day = mxYearDays(year) - mxYearDays(1970 + mxYearsOffset - 1);
1482
42.7k
  day = (day + 4) % 7;
1483
42.7k
  if (day < 0)
1484
27.7k
    day += 7; 
1485
42.7k
  return (leap) ? gxSimilarLeapYears[day] : gxSimilarCommonYears[day];
1486
69.9k
}
1487
1488
void fxDateSplit(txNumber value, txBoolean utc, txDateTime* dt)
1489
74.7k
{
1490
74.7k
  txInteger date, time, year, leap, month;
1491
74.7k
  const txInteger* monthsDays;
1492
74.7k
  date = (txInteger)c_trunc(value / mxDayMilliseconds);
1493
74.7k
  time = (txInteger)c_fmod(value, mxDayMilliseconds);
1494
74.7k
  if (time < 0) {
1495
4.07k
    date--;
1496
4.07k
    time += (txInteger)mxDayMilliseconds;
1497
4.07k
  }
1498
74.7k
  dt->offset = 0;
1499
74.7k
  dt->day = (date + 4) % 7;
1500
74.7k
  if (dt->day < 0)
1501
28.2k
    dt->day += 7; 
1502
74.7k
  dt->milliseconds = time % 1000;
1503
74.7k
  time /= 1000;
1504
74.7k
  dt->seconds = time % 60;
1505
74.7k
  time /= 60;
1506
74.7k
  dt->minutes = time % 60;
1507
74.7k
  time /= 60;
1508
74.7k
  dt->hours = time;
1509
74.7k
    date += mxYearDays(1970 + mxYearsOffset);
1510
74.7k
    year = 400 * (date / mx400YearsDays);
1511
74.7k
  date %= mx400YearsDays;
1512
74.7k
  date--;
1513
74.7k
  year += 100 * (date / mx100YearsDays);
1514
74.7k
  date %= mx100YearsDays;
1515
74.7k
  date++;
1516
74.7k
  year += 4 * (date / mx4YearsDays);
1517
74.7k
  date %= mx4YearsDays;
1518
74.7k
  date--;
1519
74.7k
  year += date / mx1YearDays;
1520
74.7k
    date %= mx1YearDays;
1521
74.7k
  year -= mxYearsOffset;
1522
74.7k
  leap = mxIsLeapYear(year);
1523
74.7k
    date += leap;
1524
74.7k
    monthsDays = leap ? gxLeapYearMonthsDays : gxCommonYearMonthsDays;
1525
483k
    for (month = 0; month < 11; month++) {
1526
481k
      if (date < monthsDays[month + 1])
1527
72.2k
        break;
1528
481k
    }
1529
74.7k
    date -= monthsDays[month];
1530
74.7k
  dt->date = date + 1;
1531
74.7k
  dt->month = month;
1532
74.7k
  dt->year = year;
1533
74.7k
  if (!utc) {
1534
42.9k
    txNumber former = value;
1535
42.9k
    txInteger similar;
1536
42.9k
    c_time_t time;
1537
42.9k
    c_tm tm;
1538
42.9k
    similar = fxDateSimilarYear(year);
1539
42.9k
    if (similar != year) {
1540
17.5k
      dt->year = similar;
1541
17.5k
      value = fxDateMerge(dt, 1);
1542
17.5k
    }
1543
42.9k
    time = (txInteger)c_floor(value / 1000.0);
1544
42.9k
    tm = *c_localtime(&time);
1545
42.9k
    dt->milliseconds = c_floor(c_fmod(value, 1000.0));
1546
42.9k
    dt->day = tm.tm_wday;
1547
42.9k
    dt->seconds = tm.tm_sec;
1548
42.9k
    dt->minutes = tm.tm_min;
1549
42.9k
    dt->hours = tm.tm_hour;
1550
42.9k
    dt->date = tm.tm_mday;
1551
42.9k
    dt->month = tm.tm_mon;
1552
42.9k
    dt->year = tm.tm_year + 1900 + year - similar;
1553
42.9k
    dt->offset = (txInteger)c_trunc((fxDateMerge(dt, 1) - former) / 60000.0);
1554
42.9k
  }
1555
74.7k
  dt->value = value;
1556
74.7k
}
1557
1558
1559
1560