Coverage Report

Created: 2026-07-14 06:35

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
26.0k
{
79
26.0k
  txSlot* slot;
80
26.0k
  mxPush(mxObjectPrototype);
81
26.0k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
82
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMilliseconds), 0, mxID(_getMilliseconds), XS_DONT_ENUM_FLAG);
83
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getSeconds), 0, mxID(_getSeconds), XS_DONT_ENUM_FLAG);
84
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMinutes), 0, mxID(_getMinutes), XS_DONT_ENUM_FLAG);
85
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getHours), 0, mxID(_getHours), XS_DONT_ENUM_FLAG);
86
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDay), 0, mxID(_getDay), XS_DONT_ENUM_FLAG);
87
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDate), 0, mxID(_getDate), XS_DONT_ENUM_FLAG);
88
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMonth), 0, mxID(_getMonth), XS_DONT_ENUM_FLAG);
89
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getYear), 0, mxID(_getYear), XS_DONT_ENUM_FLAG);
90
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getFullYear), 0, mxID(_getFullYear), XS_DONT_ENUM_FLAG);
91
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMilliseconds), 0, mxID(_getUTCMilliseconds), XS_DONT_ENUM_FLAG);
92
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCSeconds), 0, mxID(_getUTCSeconds), XS_DONT_ENUM_FLAG);
93
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMinutes), 0, mxID(_getUTCMinutes), XS_DONT_ENUM_FLAG);
94
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCHours), 0, mxID(_getUTCHours), XS_DONT_ENUM_FLAG);
95
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDay), 0, mxID(_getUTCDay), XS_DONT_ENUM_FLAG);
96
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDate), 0, mxID(_getUTCDate), XS_DONT_ENUM_FLAG);
97
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMonth), 0, mxID(_getUTCMonth), XS_DONT_ENUM_FLAG);
98
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCFullYear), 0, mxID(_getUTCFullYear), XS_DONT_ENUM_FLAG);
99
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_getTime), XS_DONT_ENUM_FLAG);
100
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getTimezoneOffset), 0, mxID(_getTimezoneOffset), XS_DONT_ENUM_FLAG);
101
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setDate), 1, mxID(_setDate), XS_DONT_ENUM_FLAG);
102
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setFullYear), 3, mxID(_setFullYear), XS_DONT_ENUM_FLAG);
103
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setHours), 4, mxID(_setHours), XS_DONT_ENUM_FLAG);
104
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMilliseconds), 1, mxID(_setMilliseconds), XS_DONT_ENUM_FLAG);
105
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMinutes), 3, mxID(_setMinutes), XS_DONT_ENUM_FLAG);
106
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMonth), 2, mxID(_setMonth), XS_DONT_ENUM_FLAG);
107
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setSeconds), 2, mxID(_setSeconds), XS_DONT_ENUM_FLAG);
108
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setTime), 1, mxID(_setTime), XS_DONT_ENUM_FLAG);
109
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setYear), 1, mxID(_setYear), XS_DONT_ENUM_FLAG);
110
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCDate), 1, mxID(_setUTCDate), XS_DONT_ENUM_FLAG);
111
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCFullYear), 3, mxID(_setUTCFullYear), XS_DONT_ENUM_FLAG);
112
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCHours), 4, mxID(_setUTCHours), XS_DONT_ENUM_FLAG);
113
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMilliseconds), 1, mxID(_setUTCMilliseconds), XS_DONT_ENUM_FLAG);
114
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMinutes), 3, mxID(_setUTCMinutes), XS_DONT_ENUM_FLAG);
115
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMonth), 2, mxID(_setUTCMonth), XS_DONT_ENUM_FLAG);
116
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCSeconds), 2, mxID(_setUTCSeconds), XS_DONT_ENUM_FLAG);
117
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toDateString), XS_DONT_ENUM_FLAG);
118
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toISOString), 0, mxID(_toISOString), XS_DONT_ENUM_FLAG);
119
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toJSON), 1, mxID(_toJSON), XS_DONT_ENUM_FLAG);
120
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toLocaleDateString), XS_DONT_ENUM_FLAG);
121
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toLocaleString), XS_DONT_ENUM_FLAG);
122
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toLocaleTimeString), XS_DONT_ENUM_FLAG);
123
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG);
124
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toTimeString), XS_DONT_ENUM_FLAG);
125
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toUTCString), 0, mxID(_toUTCString), XS_DONT_ENUM_FLAG);
126
26.0k
  slot = fxNextSlotProperty(the, slot, slot, mxID(_toGMTString), XS_DONT_ENUM_FLAG);
127
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_valueOf), XS_DONT_ENUM_FLAG);
128
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toPrimitive), 1, mxID(_Symbol_toPrimitive), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
129
26.0k
  mxDatePrototype = *the->stack;
130
26.0k
  slot = fxBuildHostConstructor(the, mxCallback(fx_Date), 7, mxID(_Date));
131
26.0k
  mxDateConstructor = *the->stack;
132
26.0k
  slot = fxLastProperty(the, slot);
133
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_now), 0, mxID(_now), XS_DONT_ENUM_FLAG);
134
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_parse), 1, mxID(_parse), XS_DONT_ENUM_FLAG);
135
26.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_UTC), 7, mxID(_UTC), XS_DONT_ENUM_FLAG);
136
26.0k
  mxPop();
137
26.0k
}
138
139
txSlot* fxNewDateInstance(txMachine* the)
140
114k
{
141
114k
  txSlot* instance;
142
114k
  txSlot* property;
143
114k
  instance = fxNewObjectInstance(the);
144
114k
  property = fxNextNumberProperty(the, instance, 0, XS_NO_ID, XS_INTERNAL_FLAG);
145
114k
  property->kind = XS_DATE_KIND;
146
114k
  property->value.number = C_NAN;
147
114k
  return instance;
148
114k
}
149
150
void fx_Date(txMachine* the)
151
126k
{
152
126k
  fx_Date_aux(the, 0);
153
126k
}
154
155
void fx_Date_aux(txMachine* the, txFlag secure)
156
126k
{
157
126k
  txInteger c = mxArgc;
158
126k
  txDateTime dt;
159
126k
  txSlot* instance;
160
126k
  if (!mxHasTarget) {
161
12.8k
    char buffer[256];
162
12.8k
    txString p = buffer;
163
12.8k
    txDateTime dt;
164
12.8k
    if (secure)
165
0
      mxTypeError("secure mode");
166
12.8k
    mxResult->value.number = fxDateNow();
167
12.8k
    mxResult->kind = XS_NUMBER_KIND;
168
12.8k
    fxDateSplit(mxResult->value.number, 0, &dt);
169
12.8k
    p = fxDatePrintDay(p, dt.day);
170
12.8k
    *p++ = ' ';
171
12.8k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
172
12.8k
    *p++ = ' ';
173
12.8k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
174
12.8k
    *p++ = ' ';
175
12.8k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
176
12.8k
    *p = 0;
177
12.8k
    fxCopyStringC(the, mxResult, buffer);
178
12.8k
    return;
179
12.8k
  }
180
114k
  mxPushSlot(mxTarget);
181
114k
  fxGetPrototypeFromConstructor(the, &mxDatePrototype);
182
114k
  instance = fxNewDateInstance(the);
183
114k
  mxPullSlot(mxResult);
184
114k
  if (c > 1) {
185
22.0k
    dt.year = fxDateFullYear(the, mxArgv(0));
186
22.0k
    dt.month = fxToNumber(the, mxArgv(1));
187
22.0k
    dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
188
22.0k
    dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
189
22.0k
    dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
190
22.0k
    dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
191
22.0k
    dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
192
22.0k
    instance->next->value.number = fxDateMerge(&dt, 0);
193
22.0k
    return;
194
22.0k
  }
195
92.0k
  if (c > 0) {
196
88.5k
    txSlot* slot = mxArgv(0);
197
88.5k
    if (slot->kind == XS_REFERENCE_KIND) {
198
750
      txSlot* date = slot->value.reference;
199
750
      if ((date->next) && (date->next->kind == XS_DATE_KIND)) {
200
160
        instance->next->value.number = date->next->value.number;
201
160
        return;
202
160
      }
203
750
    }
204
88.3k
    fxToPrimitive(the, slot, XS_NO_HINT);
205
88.3k
    if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
206
10.4k
      mxPushSlot(mxFunction);
207
10.4k
      mxDub();
208
10.4k
      mxGetID(mxID(_parse));
209
10.4k
      mxCall();
210
10.4k
      mxPushSlot(slot);
211
10.4k
      mxRunCount(1);
212
10.4k
      instance->next->value.number = the->stack->value.number;
213
10.4k
      mxPop();
214
10.4k
      return;
215
10.4k
    }
216
77.9k
    instance->next->value.number = fxDateClip(fxToNumber(the, slot));
217
77.9k
    return;
218
88.3k
  }
219
3.54k
  if (secure)
220
0
    mxTypeError("secure mode");
221
3.54k
  instance->next->value.number = fxDateNow();
222
3.54k
}
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.01M
{
242
1.01M
  txByte c = *theCharacter;
243
1.01M
  txString p = *theString;
244
1.01M
  txInteger aResult = c - '0';
245
1.01M
  c = c_read8(p++);
246
1.82M
  while (('0' <= c) && (c <= '9')) {
247
811k
#if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_mul_overflow)
248
811k
    if (__builtin_mul_overflow(aResult, 10, &aResult) ||
249
791k
      __builtin_add_overflow(aResult, c - '0', &aResult))
250
26.1k
      *overflow = 1;
251
#else
252
    aResult = (aResult * 10) + c - '0';
253
    if (aResult < 0)
254
      *overflow = 1;
255
#endif
256
811k
    c = c_read8(p++);
257
811k
  }
258
1.01M
  *theCharacter = c;
259
1.01M
  *theString = p;
260
1.01M
  return aResult;
261
1.01M
}
262
263
txInteger fx_Date_parse_fraction(txByte* theCharacter, txString* theString)
264
1.77k
{
265
1.77k
  txByte c = *theCharacter;
266
1.77k
  txString p = *theString;
267
1.77k
  txNumber fraction = 100;
268
1.77k
  txNumber aResult = ((c - '0') * fraction);
269
1.77k
  c = c_read8(p++);
270
4.36k
  while (('0' <= c) && (c <= '9')) {
271
2.59k
    fraction /= 10;
272
2.59k
    aResult = aResult + ((c - '0') * fraction);
273
2.59k
    c = c_read8(p++);
274
2.59k
  }
275
1.77k
  *theCharacter = c;
276
1.77k
  *theString = p;
277
1.77k
  return (txInteger)c_trunc(aResult);
278
1.77k
}
279
280
void fx_Date_parse(txMachine* the)
281
565k
{
282
1.70M
  #define mxDayCount 7
283
565k
  static const char* const gxDays[mxDayCount] ICACHE_RODATA_ATTR = {
284
565k
    "monday", 
285
565k
    "tuesday", 
286
565k
    "wednesday", 
287
565k
    "thursday", 
288
565k
    "friday",
289
565k
    "saturday", 
290
565k
    "sunday"
291
565k
  };
292
2.54M
  #define mxMonthCount 12
293
565k
  static const char* const gxMonths[mxMonthCount] ICACHE_RODATA_ATTR = {
294
565k
    "january",
295
565k
    "february",
296
565k
    "march",
297
565k
    "april",
298
565k
    "may",
299
565k
    "june",
300
565k
    "july",
301
565k
    "august",
302
565k
    "september",
303
565k
    "october",
304
565k
    "november",
305
565k
    "december"
306
565k
  };
307
2.27M
  #define mxZoneCount 11
308
565k
  static const char* const gxZones[mxZoneCount] ICACHE_RODATA_ATTR = {
309
565k
    "gmt", "ut", "utc",
310
565k
    "est", "edt",
311
565k
    "cst", "cdt",
312
565k
    "mst", "mdt",
313
565k
    "pst", "pdt"
314
565k
  };
315
565k
  static const int gxDeltas[mxZoneCount] ICACHE_XS6RO2_ATTR = {
316
565k
    0, 0, 0,
317
565k
    -5, -4,
318
565k
    -6, -5,
319
565k
    -7, -6,
320
565k
    -8, -7
321
565k
  };
322
  
323
565k
  txString aString;
324
565k
  txBoolean overflow = 0;
325
565k
  txDateTime dt;
326
565k
  txString p;
327
565k
  txString q;
328
565k
  txByte c;
329
565k
  char buffer[10];  /* base type should be the same as txString */
330
565k
  txInteger aComment;
331
565k
  txInteger aDelta;
332
565k
  txInteger aValue;
333
565k
  txSize aLength;
334
565k
  txInteger i;
335
565k
  txInteger yearSign = 1;
336
    
337
565k
  if (mxArgc < 1)
338
1
    goto fail;
339
565k
  aString = fxToString(the, mxArgv(0));
340
  
341
565k
  dt.seconds = -1;
342
565k
  dt.minutes = -1;
343
565k
  dt.hours = -1;
344
565k
  dt.date = -1;
345
565k
  dt.month = -1;
346
565k
  dt.year = -1;
347
565k
  dt.milliseconds = -1;
348
565k
  aComment = 0;
349
565k
  aDelta = -1;
350
351
565k
  c = c_read8(aString++);
352
2.95M
  while (c) {
353
2.93M
    if (c == '(') {
354
1.38k
      aComment++;
355
1.38k
      c = c_read8(aString++);
356
1.38k
      continue;
357
1.38k
    }
358
2.93M
    else if (c == ')') {
359
8.70k
      if (aComment) {
360
388
        aComment--;
361
388
        c = c_read8(aString++);
362
388
        continue;
363
388
      }
364
8.32k
      else
365
8.32k
        goto fail;
366
8.70k
    }
367
2.92M
    else if (aComment) {
368
14.3k
      c = c_read8(aString++);
369
14.3k
      continue;
370
14.3k
    }  
371
    
372
2.90M
    if ((c <= ' ') || (c == ',')) {
373
1.80M
      c = c_read8(aString++);
374
1.80M
      continue;
375
1.80M
    }
376
      
377
1.10M
    else if ((c == '-') | (c == '+')) {
378
22.2k
            txInteger aSign;
379
22.2k
      if (c == '-')  
380
20.8k
        aSign = -1;
381
1.39k
      else
382
1.39k
        aSign = 1;
383
22.2k
      c = c_read8(aString++);
384
22.2k
      if (('0' <= c) && (c <= '9')) {
385
21.5k
        aValue = fx_Date_parse_number(&c, &aString, &overflow);
386
21.5k
        if (c == '-') {
387
5.26k
          if (dt.year >= 0)
388
910
            goto fail;
389
4.35k
          dt.year = aValue;
390
4.35k
          yearSign = aSign;
391
4.35k
          c = c_read8(aString++);
392
4.35k
          if (('0' <= c) && (c <= '9')) {
393
3.09k
            dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
394
3.09k
            if (c == '-') {
395
1.45k
              c = c_read8(aString++);
396
1.45k
              if (('0' <= c) && (c <= '9'))
397
1.20k
                dt.date = fx_Date_parse_number(&c, &aString, &overflow);
398
255
              else
399
255
                dt.date = 1;
400
1.45k
            }
401
3.09k
          }
402
1.26k
          else
403
1.26k
            dt.month = 0;
404
4.35k
        }
405
16.3k
        else {
406
16.3k
          if ((aDelta != 0) && (aDelta != -1))
407
1.19k
            goto fail;
408
15.1k
          if (c == ':') {
409
3.06k
            aDelta = 60 * aValue;
410
3.06k
            c = c_read8(aString++);
411
3.06k
            if (('0' <= c) && (c <= '9')) {
412
1.24k
              aDelta += fx_Date_parse_number(&c, &aString, &overflow);
413
1.24k
            }
414
3.06k
          }
415
12.0k
          else {
416
12.0k
            if (aValue < 24)
417
7.49k
              aDelta = aValue * 60;
418
4.54k
            else
419
4.54k
              aDelta = (aValue % 100) + ((aValue / 100) * 60);
420
12.0k
          }
421
15.1k
          aDelta *= aSign;
422
15.1k
        }
423
21.5k
      }
424
698
      else
425
698
        goto fail;
426
22.2k
    }    
427
1.08M
    else if (('0' <= c) && (c <= '9')) {
428
495k
      aValue = fx_Date_parse_number(&c, &aString, &overflow);
429
495k
      if (c == ':') {
430
58.3k
        if (dt.hours >= 0) 
431
328
          goto fail;
432
57.9k
        dt.hours = aValue;  
433
57.9k
        c = c_read8(aString++);
434
57.9k
        if (('0' <= c) && (c <= '9')) {
435
49.0k
          dt.minutes = fx_Date_parse_number(&c, &aString, &overflow);
436
49.0k
          if (c == ':') {
437
46.7k
            c = c_read8(aString++);
438
46.7k
            if (('0' <= c) && (c <= '9')) {
439
42.3k
              dt.seconds = fx_Date_parse_number(&c, &aString, &overflow);
440
42.3k
              if (c == '.') {
441
2.83k
                c = c_read8(aString++);
442
2.83k
                if (('0' <= c) && (c <= '9')) {
443
1.77k
                  dt.milliseconds = fx_Date_parse_fraction(&c, &aString);
444
1.77k
                }
445
2.83k
              }
446
42.3k
            }
447
4.31k
            else
448
4.31k
              dt.seconds = 0;
449
46.7k
          }
450
49.0k
        }
451
8.96k
        else
452
8.96k
          dt.seconds = 0;
453
57.9k
      }
454
437k
      else if (c == '/') {
455
6.80k
        if (dt.year >= 0)
456
332
          goto fail;
457
6.46k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
458
6.46k
        c = c_read8(aString++);
459
6.46k
        if (('0' <= c) && (c <= '9')) {
460
5.45k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
461
5.45k
          if (c == '/') {
462
2.54k
            c = c_read8(aString++);
463
2.54k
            if (('0' <= c) && (c <= '9')) {
464
383
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
465
383
            }
466
2.16k
            else
467
2.16k
              dt.date = 1;
468
2.54k
          }
469
5.45k
        }
470
1.01k
        else
471
1.01k
          dt.month = 0;
472
6.46k
      }
473
430k
      else if (c == '-') {
474
394k
        if (dt.year >= 0)
475
582
          goto fail;
476
393k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
477
393k
        c = c_read8(aString++);
478
393k
        if (('0' <= c) && (c <= '9')) {
479
392k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
480
392k
          if (c == '-') {
481
3.88k
            c = c_read8(aString++);
482
3.88k
            if (('0' <= c) && (c <= '9'))
483
1.45k
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
484
2.42k
            else
485
2.42k
              dt.date = 1;
486
3.88k
          }
487
392k
        }
488
1.22k
        else
489
1.22k
          dt.month = 0;
490
393k
      }
491
36.2k
      else {
492
36.2k
        if (aValue < 70) {
493
28.0k
          if (dt.date < 0)
494
22.6k
            dt.date = aValue;
495
5.41k
          else
496
5.41k
            goto fail;
497
28.0k
        }
498
8.20k
        else {
499
8.20k
          if (dt.year < 0)
500
7.64k
            dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
501
561
          else
502
561
            goto fail;
503
8.20k
        }
504
36.2k
      }
505
495k
    }        
506
588k
    else if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'))) {
507
207k
      txSize cmpLength;
508
207k
      p = buffer;
509
207k
      q = p + sizeof(buffer) - 1;
510
321k
      do {
511
321k
        if (p == q) goto fail;
512
318k
        *p++ = (c >= 'a') ? c : (c + ('a' - 'A'));
513
318k
        c = c_read8(aString++);
514
318k
      } while ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')));
515
204k
      *p = 0;
516
204k
      aLength = mxPtrDiff(p - (txString)buffer);
517
204k
      cmpLength = (aLength >= 3) ? aLength : 3;
518
204k
      if (c_strcmp("am", buffer) == 0) {
519
5.23k
        if ((dt.hours < 0) || (12 <  dt.hours))
520
2.63k
          goto fail;
521
2.60k
        if (dt.hours == 12)
522
1.59k
          dt.hours = 0;
523
2.60k
        continue;
524
5.23k
      }
525
198k
      if (c_strcmp("pm", buffer) == 0) {
526
6.24k
        if ((dt.hours < 0) || (12 <  dt.hours))
527
2.65k
          goto fail;
528
3.59k
        if (dt.hours != 12)
529
2.30k
          dt.hours += 12;
530
3.59k
        continue;
531
6.24k
      }
532
1.51M
      for (i = 0; i < mxDayCount; i++)
533
1.32M
        if (c_strncmp(gxDays[i], buffer, cmpLength) == 0)
534
7.44k
          break;
535
192k
      if (i < mxDayCount)
536
7.44k
        continue;
537
2.35M
      for (i = 0; i < mxMonthCount; i++)
538
2.17M
        if (c_strncmp(gxMonths[i], buffer, cmpLength) == 0)
539
7.43k
          break;
540
185k
      if (i < mxMonthCount) {
541
7.43k
        if (dt.month < 0) {
542
7.32k
          dt.month = i;
543
7.32k
          continue;
544
7.32k
        }
545
112
        else
546
112
          goto fail;
547
7.43k
      }
548
2.09M
      for (i = 0; i < mxZoneCount; i++)
549
1.91M
        if (c_strcmp(gxZones[i], buffer) == 0)
550
3.89k
          break;
551
177k
      if (i < mxZoneCount) {
552
3.89k
        if (aDelta == -1) {
553
611
          aDelta = gxDeltas[i] * 60;
554
611
          continue;
555
611
        }
556
3.27k
        else
557
3.27k
          goto fail;
558
3.89k
      }
559
173k
      if (c_strcmp("t", buffer) == 0) {
560
38.2k
        if (dt.year < 0) 
561
261
          goto fail;
562
37.9k
        continue;
563
38.2k
      }
564
135k
      if (c_strcmp("z", buffer) == 0) {
565
5.79k
        if (dt.hours < 0) 
566
2.25k
          goto fail;
567
3.54k
        aDelta = 0;
568
3.54k
        continue;
569
5.79k
      }
570
129k
      goto fail;
571
135k
    }
572
381k
    else
573
381k
      goto fail;
574
2.90M
  }
575
21.7k
   if (overflow)
576
411
       goto fail;
577
21.2k
   if (dt.year < 0)
578
9.01k
       goto fail;
579
12.2k
  if ((yearSign < 0) && (dt.year == 0))
580
252
       goto fail;
581
12.0k
  if (dt.month < 0)
582
1.70k
    dt.month = 0;
583
12.0k
  if (dt.date < 0)
584
2.03k
    dt.date = 1;
585
12.0k
  if ((aDelta < 0) && (dt.hours < 0) && (dt.minutes < 0) && (dt.seconds < 0) && (dt.milliseconds < 0))
586
540
    aDelta = 0;
587
12.0k
  if (dt.hours < 0)
588
544
    dt.hours = 0;
589
12.0k
  if (dt.minutes < 0)
590
971
    dt.minutes = 0;
591
12.0k
    if (dt.seconds < 0)
592
1.46k
        dt.seconds = 0;
593
12.0k
    if (dt.milliseconds < 0)
594
11.2k
        dt.milliseconds = 0;
595
12.0k
    dt.year *= yearSign;
596
12.0k
  mxResult->value.number = fxDateMerge(&dt, (aDelta != -1) ? 1 : 0);
597
12.0k
  if (aDelta != -1)
598
2.01k
    mxResult->value.number -= (txNumber)aDelta * 60000.0;
599
12.0k
  mxResult->kind = XS_NUMBER_KIND;
600
12.0k
  return;
601
553k
fail:
602
553k
  mxResult->value.number = C_NAN;
603
553k
  mxResult->kind = XS_NUMBER_KIND;
604
  //mxSyntaxError("invalid parameter");
605
553k
}
606
607
void fx_Date_UTC(txMachine* the)
608
160k
{
609
160k
  txInteger c = mxArgc;
610
160k
  txDateTime dt;
611
160k
  dt.year = (c > 0) ? fxDateFullYear(the, mxArgv(0)) : C_NAN;
612
160k
  dt.month = (c > 1) ? fxToNumber(the, mxArgv(1)) : 0;
613
160k
  dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
614
160k
  dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
615
160k
  dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
616
160k
  dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
617
160k
  dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
618
160k
  mxResult->value.number = fxDateMerge(&dt, 1);
619
160k
    mxResult->kind = XS_NUMBER_KIND;
620
160k
}
621
622
txBoolean fx_Date_prototype_get_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
623
109k
{
624
109k
  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
109k
  number = slot->value.number;
636
109k
  if (c_isnan(number)) {
637
81.6k
    mxResult->value.number = C_NAN;
638
81.6k
    mxResult->kind = XS_NUMBER_KIND;
639
81.6k
    dt->value = C_NAN;
640
81.6k
    return 0;
641
81.6k
  }
642
27.5k
  fxDateSplit(slot->value.number, utc, dt);
643
27.5k
  return 1;
644
109k
}
645
646
void fx_Date_prototype_set_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
647
464
{
648
464
  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
464
  if (c_isnan(number))
661
135
    return;
662
329
  if (slot->flag & XS_DONT_SET_FLAG)
663
0
    mxTypeError("this: read-only Date instance");
664
329
  mxResult->value.number = slot->value.number = fxDateMerge(dt, utc);
665
329
  mxResult->kind = XS_NUMBER_KIND;
666
329
}
667
668
void fx_Date_prototype_getMilliseconds(txMachine* the)
669
74
{
670
74
  txDateTime dt;
671
74
  txSlot* slot = fxDateCheck(the);
672
74
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
673
25
    mxResult->value.integer = (txInteger)dt.milliseconds;
674
25
    mxResult->kind = XS_INTEGER_KIND;
675
25
  }
676
74
}
677
678
void fx_Date_prototype_getSeconds(txMachine* the)
679
30
{
680
30
  txDateTime dt;
681
30
  txSlot* slot = fxDateCheck(the);
682
30
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
683
12
    mxResult->value.integer = (txInteger)dt.seconds;
684
12
    mxResult->kind = XS_INTEGER_KIND;
685
12
  }
686
30
}
687
688
void fx_Date_prototype_getMinutes(txMachine* the)
689
39
{
690
39
  txDateTime dt;
691
39
  txSlot* slot = fxDateCheck(the);
692
39
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
693
21
    mxResult->value.integer = (txInteger)dt.minutes;
694
21
    mxResult->kind = XS_INTEGER_KIND;
695
21
  }
696
39
}
697
698
void fx_Date_prototype_getHours(txMachine* the)
699
30
{
700
30
  txDateTime dt;
701
30
  txSlot* slot = fxDateCheck(the);
702
30
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
703
15
    mxResult->value.integer = (txInteger)dt.hours;
704
15
    mxResult->kind = XS_INTEGER_KIND;
705
15
  }
706
30
}
707
708
void fx_Date_prototype_getDay(txMachine* the)
709
76.0k
{
710
76.0k
  txDateTime dt;
711
76.0k
  txSlot* slot = fxDateCheck(the);
712
76.0k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
713
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
44
{
720
44
  txDateTime dt;
721
44
  txSlot* slot = fxDateCheck(the);
722
44
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
723
21
    mxResult->value.integer = (txInteger)dt.date;
724
21
    mxResult->kind = XS_INTEGER_KIND;
725
21
  }
726
44
}
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
51
{
750
51
  txDateTime dt;
751
51
  txSlot* slot = fxDateCheck(the);
752
51
  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
51
}
757
758
void fx_Date_prototype_getUTCMilliseconds(txMachine* the)
759
75
{
760
75
  txDateTime dt;
761
75
  txSlot* slot = fxDateCheck(the);
762
75
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
763
12
    mxResult->value.integer = (txInteger)dt.milliseconds;
764
12
    mxResult->kind = XS_INTEGER_KIND;
765
12
  }
766
75
}
767
768
void fx_Date_prototype_getUTCSeconds(txMachine* the)
769
460
{
770
460
  txDateTime dt;
771
460
  txSlot* slot = fxDateCheck(the);
772
460
  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
460
}
777
778
void fx_Date_prototype_getUTCMinutes(txMachine* the)
779
32
{
780
32
  txDateTime dt;
781
32
  txSlot* slot = fxDateCheck(the);
782
32
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
783
11
    mxResult->value.integer = (txInteger)dt.minutes;
784
11
    mxResult->kind = XS_INTEGER_KIND;
785
11
  }
786
32
}
787
788
void fx_Date_prototype_getUTCHours(txMachine* the)
789
42
{
790
42
  txDateTime dt;
791
42
  txSlot* slot = fxDateCheck(the);
792
42
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
793
19
    mxResult->value.integer = (txInteger)dt.hours;
794
19
    mxResult->kind = XS_INTEGER_KIND;
795
19
  }
796
42
}
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
39
{
810
39
  txDateTime dt;
811
39
  txSlot* slot = fxDateCheck(the);
812
39
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
813
19
    mxResult->value.integer = (txInteger)dt.date;
814
19
    mxResult->kind = XS_INTEGER_KIND;
815
19
  }
816
39
}
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
50
{
830
50
  txDateTime dt;
831
50
  txSlot* slot = fxDateCheck(the);
832
50
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
833
14
    mxResult->value.integer = (txInteger)dt.year;
834
14
    mxResult->kind = XS_INTEGER_KIND;
835
14
  }
836
50
}
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
16
    mxResult->value.integer = 0 - dt.offset;
844
16
    mxResult->kind = XS_INTEGER_KIND;
845
16
  }
846
43
}
847
848
void fx_Date_prototype_setMilliseconds(txMachine* the)
849
47
{
850
47
  txInteger c = mxArgc;
851
47
  txDateTime dt;
852
47
  txSlot* slot = fxDateCheck(the);
853
47
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
854
47
  dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
855
47
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
856
47
}
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.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
79
{
883
79
  txInteger c = mxArgc;
884
79
  txDateTime dt;
885
79
  txSlot* slot = fxDateCheck(the);
886
79
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
887
79
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
888
79
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
889
79
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
890
79
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
891
79
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
892
79
}
893
894
void fx_Date_prototype_setDate(txMachine* the)
895
66
{
896
66
  txInteger c = mxArgc;
897
66
  txDateTime dt;
898
66
  txSlot* slot = fxDateCheck(the);
899
66
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
900
66
  dt.date = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
901
66
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
902
66
}
903
904
void fx_Date_prototype_setMonth(txMachine* the)
905
344
{
906
344
  txInteger c = mxArgc;
907
344
  txDateTime dt;
908
344
  txSlot* slot = fxDateCheck(the);
909
344
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
910
344
  dt.month = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
911
344
  if (c > 1) dt.date = fxToNumber(the, mxArgv(1));
912
344
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
913
344
}
914
915
void fx_Date_prototype_setYear(txMachine* the)
916
0
{
917
0
  txInteger c = mxArgc;
918
0
  txDateTime dt;
919
0
  txSlot* slot = fxDateCheck(the);
920
0
  if (c_isnan(slot->value.number)) {
921
0
    slot->value.number = 0;
922
0
    fx_Date_prototype_get_aux(the, &dt, 1, slot);
923
0
  }
924
0
  else
925
0
    fx_Date_prototype_get_aux(the, &dt, 0, slot);
926
0
  dt.year = (mxArgc > 0) ? fxDateFullYear(the, mxArgv(0)) : C_NAN;
927
0
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
928
0
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
929
0
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
930
0
}
931
932
void fx_Date_prototype_setFullYear(txMachine* the)
933
1.89k
{
934
1.89k
  txInteger c = mxArgc;
935
1.89k
  txDateTime dt;
936
1.89k
  txSlot* slot = fxDateCheck(the);
937
1.89k
  if (c_isnan(slot->value.number)) {
938
8
    slot->value.number = 0;
939
8
    fx_Date_prototype_get_aux(the, &dt, 1, slot);
940
8
  }
941
1.88k
  else
942
1.88k
    fx_Date_prototype_get_aux(the, &dt, 0, slot);
943
1.89k
  dt.year = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
944
1.89k
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
945
1.89k
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
946
1.89k
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
947
1.89k
}
948
949
void fx_Date_prototype_setTime(txMachine* the)
950
82
{
951
82
  txSlot* slot = fxDateCheck(the);
952
82
  if (slot->flag & XS_DONT_SET_FLAG)
953
0
    mxTypeError("this: read-only Date instance");
954
82
  if (mxArgc < 1)
955
3
    slot->value.number = C_NAN;
956
79
  else {
957
79
    txNumber number = fxToNumber(the, mxArgv(0));
958
79
    int fpclass = c_fpclassify(number);
959
79
    if (fpclass != C_FP_NAN) {
960
34
      if (c_fabs(number) > 8.64e15)
961
1
        number = C_NAN;
962
33
      else
963
33
        number = c_trunc(number);
964
34
    }
965
79
    slot->value.number = number;
966
79
  }
967
82
  mxResult->value.number = slot->value.number;
968
82
  mxResult->kind = XS_NUMBER_KIND;
969
82
}
970
971
void fx_Date_prototype_setUTCMilliseconds(txMachine* the)
972
7
{
973
7
  txInteger c = mxArgc;
974
7
  txDateTime dt;
975
7
  txSlot* slot = fxDateCheck(the);
976
7
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
977
7
  dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
978
7
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
979
7
}
980
981
void fx_Date_prototype_setUTCSeconds(txMachine* the)
982
13
{
983
13
  txInteger c = mxArgc;
984
13
  txDateTime dt;
985
13
  txSlot* slot = fxDateCheck(the);
986
13
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
987
13
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
988
13
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
989
13
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
990
13
}
991
992
void fx_Date_prototype_setUTCMinutes(txMachine* the)
993
34
{
994
34
  txInteger c = mxArgc;
995
34
  txDateTime dt;
996
34
  txSlot* slot = fxDateCheck(the);
997
34
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
998
34
  dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
999
34
  if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1));
1000
34
  if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2));
1001
34
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1002
34
}
1003
1004
void fx_Date_prototype_setUTCHours(txMachine* the)
1005
22
{
1006
22
  txInteger c = mxArgc;
1007
22
  txDateTime dt;
1008
22
  txSlot* slot = fxDateCheck(the);
1009
22
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1010
22
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1011
22
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
1012
22
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
1013
22
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
1014
22
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1015
22
}
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.31k
{
1053
2.31k
  char buffer[256];
1054
2.31k
  txDateTime dt;
1055
2.31k
  txSlot* slot = fxDateCheck(the);
1056
2.31k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1057
1.62k
    txString p = buffer;
1058
1.62k
    p = fxDatePrintDay(p, dt.day);
1059
1.62k
    *p++ = ' ';
1060
1.62k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1061
1.62k
    *p = 0;
1062
1.62k
  }
1063
697
  else
1064
697
    c_strcpy(buffer, "Invalid Date");
1065
2.31k
  fxCopyStringC(the, mxResult, buffer);
1066
2.31k
}
1067
1068
void fx_Date_prototype_toISOString(txMachine* the)
1069
29
{
1070
29
  char buffer[256];
1071
29
  txDateTime dt;
1072
29
  txSlot* slot = fxDateCheck(the);
1073
29
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
1074
23
    txString p = buffer;
1075
23
    p = fxDatePrintYear(p, (txInteger)dt.year);
1076
23
    *p++ = '-';
1077
23
    p = fxDatePrint2Digits(p, (txInteger)dt.month + 1);
1078
23
    *p++ = '-';
1079
23
    p = fxDatePrint2Digits(p, (txInteger)dt.date);
1080
23
    *p++ = 'T';
1081
23
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1082
23
    *p++ = '.';
1083
23
    p = fxDatePrint3Digits(p, (txInteger)dt.milliseconds);
1084
23
    *p++ = 'Z';
1085
23
    *p = 0;
1086
23
  }
1087
6
  else
1088
6
        mxRangeError("Invalid Date");
1089
23
  fxCopyStringC(the, mxResult, buffer);
1090
23
}
1091
1092
void fx_Date_prototype_toJSON(txMachine* the)
1093
14
{
1094
14
  fxToInstance(the, mxThis);
1095
14
  mxPushSlot(mxThis);
1096
14
  fxToPrimitive(the, the->stack, XS_NUMBER_HINT);
1097
14
  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
8
  else {   
1102
8
    mxPop();
1103
8
    mxPushSlot(mxThis);
1104
8
    mxDub();
1105
8
    mxGetID(mxID(_toISOString));
1106
8
    mxCall();
1107
8
    mxRunCount(0);
1108
8
    mxPullSlot(mxResult);
1109
8
  }
1110
14
}
1111
1112
void fx_Date_prototype_toPrimitive(txMachine* the)
1113
31.7k
{
1114
31.7k
  if (mxIsReference(mxThis)) {
1115
31.7k
    txInteger hint = XS_NO_HINT;
1116
31.7k
    txInteger ids[2], i;
1117
31.7k
    if (mxArgc > 0) {
1118
31.7k
      txSlot* slot = mxArgv(0);
1119
31.7k
      if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
1120
31.7k
        if (!c_strcmp(slot->value.string, "default"))
1121
20.9k
          hint = XS_STRING_HINT;
1122
10.7k
        else if (!c_strcmp(slot->value.string, "number"))
1123
10.5k
          hint = XS_NUMBER_HINT;
1124
254
        else if (!c_strcmp(slot->value.string, "string"))
1125
243
          hint = XS_STRING_HINT;
1126
31.7k
      }
1127
31.7k
    }
1128
31.7k
    if (hint == XS_STRING_HINT) {
1129
21.1k
      ids[0] = mxID(_toString);
1130
21.1k
      ids[1] = mxID(_valueOf);
1131
21.1k
    }
1132
10.5k
    else if (hint == XS_NUMBER_HINT) {
1133
10.5k
      ids[0] = mxID(_valueOf);
1134
10.5k
      ids[1] = mxID(_toString);
1135
10.5k
    }
1136
25
    else
1137
25
        mxTypeError("invalid hint");
1138
31.7k
    for (i = 0; i < 2; i++) {
1139
31.7k
      mxPushSlot(mxThis);
1140
31.7k
      mxPushSlot(mxThis);
1141
31.7k
      mxGetID(ids[i]);
1142
31.7k
      if (fxIsCallable(the, the->stack)) {
1143
31.7k
        mxCall();
1144
31.7k
        mxRunCount(0);
1145
31.7k
        if (mxIsReference(the->stack))
1146
1
          mxPop();
1147
31.7k
        else {
1148
31.7k
          mxPullSlot(mxResult);
1149
31.7k
          return;
1150
31.7k
            }
1151
31.7k
      }
1152
5
      else {
1153
5
        mxPop();
1154
5
        mxPop();
1155
5
      }
1156
31.7k
    }
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
31.7k
}
1166
1167
void fx_Date_prototype_toString(txMachine* the)
1168
21.2k
{
1169
21.2k
  char buffer[256];
1170
21.2k
  txDateTime dt;
1171
21.2k
  txSlot* slot = fxDateCheck(the);
1172
21.2k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1173
18.9k
    txString p = buffer;
1174
18.9k
    p = fxDatePrintDay(p, dt.day);
1175
18.9k
    *p++ = ' ';
1176
18.9k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1177
18.9k
    *p++ = ' ';
1178
18.9k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1179
18.9k
    *p++ = ' ';
1180
18.9k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
1181
18.9k
    *p = 0;
1182
18.9k
  }
1183
2.27k
  else
1184
2.27k
    c_strcpy(buffer, "Invalid Date");
1185
21.2k
  fxCopyStringC(the, mxResult, buffer);
1186
21.2k
}
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.08k
{
1207
1.08k
  char buffer[256];
1208
1.08k
  txDateTime dt;
1209
1.08k
  txSlot* slot = fxDateCheck(the);
1210
1.08k
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
1211
895
    txString p = buffer;
1212
895
    p = fxDatePrintDay(p, dt.day);
1213
895
    *p++ = ',';
1214
895
    *p++ = ' ';
1215
895
    p = fxDatePrintDateUTC(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1216
895
    *p++ = ' ';
1217
895
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1218
895
    *p++ = ' ';
1219
895
    *p++ = 'G';
1220
895
    *p++ = 'M';
1221
895
    *p++ = 'T';
1222
895
    *p = 0;
1223
895
  }
1224
193
  else
1225
193
    c_strcpy(buffer, "Invalid Date");
1226
1.08k
  fxCopyStringC(the, mxResult, buffer);
1227
1.08k
}
1228
1229
void fx_Date_prototype_valueOf(txMachine* the)
1230
10.9k
{
1231
10.9k
  txSlot* slot = fxDateCheck(the);
1232
10.9k
  mxResult->kind = XS_NUMBER_KIND;
1233
10.9k
  mxResult->value = slot->value;
1234
10.9k
}
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
572k
#define mx1YearDays 365
1259
429k
#define mx4YearsDays ((4 * mx1YearDays) + 1)
1260
286k
#define mx100YearsDays ((25 * mx4YearsDays) - 1)
1261
143k
#define mx400YearsDays ((4 * mx100YearsDays) + 1)
1262
422k
#define mxDayMilliseconds 86400000.0
1263
#define mxYearDays(YEAR) \
1264
442k
  ((365 * (YEAR)) + ((YEAR) / 4) - ((YEAR) / 100) + ((YEAR) / 400) + 1)
1265
#define mxIsLeapYear(YEAR) \
1266
118k
  (((YEAR) % 4) ? 0 : ((YEAR) % 100) ? 1 : ((YEAR) % 400) ? 0 : 1)
1267
395k
#define mxYearsOffset 400000
1268
1269
txSlot* fxDateCheck(txMachine* the)
1270
120k
{
1271
120k
  txSlot* it = mxThis;
1272
120k
  if (it->kind == XS_REFERENCE_KIND) {
1273
120k
    txSlot* instance = it->value.reference;
1274
120k
    it = instance->next;
1275
120k
    if ((it) && (it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_DATE_KIND))
1276
120k
      return it;
1277
120k
  }
1278
120k
  mxTypeError("this: not a Date instance");
1279
0
  return C_NULL;
1280
120k
}
1281
1282
txNumber fxDateClip(txNumber value)
1283
385k
{
1284
385k
  if (!c_isfinite(value))
1285
76.2k
    value = C_NAN;
1286
308k
  else if (c_fabs(value) > 8.64e15)
1287
5.81k
    value = C_NAN;
1288
303k
  else {
1289
303k
    value = c_trunc(value);
1290
303k
    if (value == 0)
1291
2.77k
      value = 0;
1292
303k
  }
1293
385k
  return value; 
1294
385k
}
1295
1296
txNumber fxDateFullYear(txMachine* the, txSlot* slot)
1297
182k
{
1298
182k
  txNumber result = fxToNumber(the, slot);
1299
182k
  if (c_isfinite(result)) {
1300
180k
    txInteger value = fxToInteger(the, slot);
1301
180k
    if ((0 <= value) && (value <= 99))
1302
167k
      result = 1900 + value;
1303
180k
  }
1304
182k
  return result;
1305
182k
}
1306
1307
txNumber fxDateMerge(txDateTime* dt, txBoolean utc)
1308
280k
{
1309
280k
  txNumber year, month;
1310
280k
  txInteger monthIndex;
1311
280k
  txBoolean leap;
1312
280k
  txNumber value;
1313
280k
  if ((!c_isfinite(dt->year))
1314
278k
  || (!c_isfinite(dt->month))
1315
278k
  || (!c_isfinite(dt->date))
1316
278k
  || (!c_isfinite(dt->hours))
1317
277k
  || (!c_isfinite(dt->minutes))
1318
277k
  || (!c_isfinite(dt->seconds))
1319
277k
  || (!c_isfinite(dt->milliseconds)))
1320
3.89k
    return C_NAN;
1321
276k
  year = c_trunc(dt->year);
1322
276k
  month = c_trunc(dt->month);
1323
276k
  year += c_floor(month / 12);
1324
276k
  monthIndex = (txInteger)c_fmod(month, 12.0);
1325
276k
  if (monthIndex < 0)
1326
747
    monthIndex += 12;
1327
276k
  leap = (c_fmod(year, 4) == 0) && ((c_fmod(year, 100) != 0) || (c_fmod(year, 400) == 0));
1328
276k
  year += mxYearsOffset - 1;
1329
276k
  value = (365 * year) + c_floor(year / 4) - c_floor(year / 100) + c_floor(year / 400) + 1;
1330
276k
  value -= (txNumber)mxYearDays(1970 + mxYearsOffset - 1);
1331
276k
  if (leap)
1332
21.5k
    value += gxLeapYearMonthsDays[monthIndex];
1333
255k
  else
1334
255k
    value += gxCommonYearMonthsDays[monthIndex];
1335
276k
  value += c_trunc(dt->date) - 1;
1336
276k
  value *= mxDayMilliseconds;
1337
276k
  value += c_trunc(dt->hours) * 60 * 60 * 1000;
1338
276k
  value += c_trunc(dt->minutes) * 60 * 1000;
1339
276k
  value += c_trunc(dt->seconds) * 1000;
1340
276k
    value += c_trunc(dt->milliseconds);
1341
276k
  if (!utc) {
1342
31.0k
    txNumber former = value;
1343
31.0k
    txInteger similar;
1344
31.0k
    c_tm tm;
1345
31.0k
    c_time_t time;
1346
31.0k
    fxDateSplit(value, 1, dt);
1347
31.0k
    similar = fxDateSimilarYear((txInteger)dt->year);
1348
31.0k
    c_memset(&tm, 0, sizeof(c_tm));
1349
31.0k
    tm.tm_year = similar - 1900;
1350
31.0k
    tm.tm_mon = (txInteger)dt->month;
1351
31.0k
    tm.tm_mday = (txInteger)dt->date;
1352
31.0k
    tm.tm_hour = (txInteger)dt->hours;
1353
31.0k
    tm.tm_min = (txInteger)dt->minutes;
1354
31.0k
    tm.tm_sec = (txInteger)dt->seconds;
1355
31.0k
    tm.tm_isdst =-1;
1356
31.0k
    time = c_mktime(&tm);  
1357
31.0k
    if (time == -1)
1358
0
      value = NAN;
1359
31.0k
    else {
1360
31.0k
      value = (txNumber)time;
1361
31.0k
      value *= 1000;
1362
31.0k
      value += dt->milliseconds;
1363
31.0k
      if (similar != year) {
1364
31.0k
        dt->year = similar;
1365
31.0k
        value += former - fxDateMerge(dt, 1);
1366
31.0k
      }
1367
31.0k
    }
1368
31.0k
  }
1369
276k
  return fxDateClip(value);
1370
280k
}
1371
1372
txNumber fxDateNow()
1373
30.6k
{
1374
30.6k
  c_timeval tv;
1375
30.6k
  c_gettimeofday(&tv, NULL);
1376
30.6k
  return fxDateClip(((txNumber)(tv.tv_sec) * 1000.0) + ((txNumber)(tv.tv_usec / 1000)));
1377
30.6k
}
1378
1379
txString fxDatePrint2Digits(txString p, txInteger value)
1380
230k
{
1381
230k
  *p++ = '0' + value / 10;
1382
230k
  *p++ = '0' + value % 10;
1383
230k
  return p;
1384
230k
}
1385
1386
txString fxDatePrint3Digits(txString p, txInteger value)
1387
34.3k
{
1388
34.3k
  *p++ = '0' + value / 100;
1389
34.3k
  return fxDatePrint2Digits(p, value % 100);
1390
34.3k
}
1391
1392
txString fxDatePrint4Digits(txString p, txInteger value)
1393
34.3k
{
1394
34.3k
  *p++ = '0' + value / 1000;
1395
34.3k
  return fxDatePrint3Digits(p, value % 1000);
1396
34.3k
}
1397
1398
txString fxDatePrintDate(txString p, txInteger year, txInteger month, txInteger date)
1399
33.4k
{
1400
33.4k
  c_strcpy(p, gxMonthNames[month]);
1401
33.4k
  p += 3;
1402
33.4k
  *p++ = ' ';
1403
33.4k
  p = fxDatePrint2Digits(p, date);
1404
33.4k
  *p++ = ' ';
1405
33.4k
  p = fxDatePrintYear(p, year);
1406
33.4k
  return p;
1407
33.4k
}
1408
1409
txString fxDatePrintDateUTC(txString p, txInteger year, txInteger month, txInteger date)
1410
895
{
1411
895
  p = fxDatePrint2Digits(p, date);
1412
895
  *p++ = ' ';
1413
895
  c_strcpy(p, gxMonthNames[month]);
1414
895
  p += 3;
1415
895
  *p++ = ' ';
1416
895
  p = fxDatePrintYear(p, year);
1417
895
  return p;
1418
895
}
1419
1420
txString fxDatePrintDay(txString p, txInteger day)
1421
34.3k
{
1422
34.3k
  c_strcpy(p, gxDayNames[day]);
1423
34.3k
  p += 3;
1424
34.3k
  return p;
1425
34.3k
}
1426
1427
txString fxDatePrintTime(txString p, txInteger hours, txInteger minutes, txInteger seconds)
1428
32.7k
{
1429
32.7k
  p = fxDatePrint2Digits(p, hours);
1430
32.7k
  *p++ = ':';
1431
32.7k
  p = fxDatePrint2Digits(p, minutes);
1432
32.7k
  *p++ = ':';
1433
32.7k
  p = fxDatePrint2Digits(p, seconds);
1434
32.7k
  return p;
1435
32.7k
}
1436
1437
txString fxDatePrintTimezone(txString p, txInteger offset)
1438
31.8k
{
1439
31.8k
  *p++ = 'G';
1440
31.8k
  *p++ = 'M';
1441
31.8k
  *p++ = 'T';
1442
31.8k
  if (offset < 0) {
1443
0
    offset = 0 - offset;
1444
0
    *p++ = '-';
1445
0
  }
1446
31.8k
  else
1447
31.8k
    *p++ = '+';
1448
31.8k
  p = fxDatePrint2Digits(p, offset / 60);
1449
31.8k
  p = fxDatePrint2Digits(p, offset % 60);
1450
31.8k
  return p;
1451
31.8k
}
1452
1453
txString fxDatePrintYear(txString p, txInteger value)
1454
34.3k
{
1455
34.3k
  if ((value < 0) || (9999 < value)) {
1456
4.14k
    if (value < 0) {
1457
3.19k
      *p++ = '-';
1458
3.19k
      value = -value;
1459
3.19k
    }
1460
944
    else
1461
944
      *p++ = '+';
1462
4.14k
    if (99999 < value) {
1463
1.34k
      *p++ = '0' + value / 100000;
1464
1.34k
      value %= 100000;
1465
1.34k
    }
1466
4.14k
    if (9999 < value) {
1467
3.04k
      *p++ = '0' + value / 10000;
1468
3.04k
      value %= 10000;
1469
3.04k
    }
1470
4.14k
  }
1471
34.3k
  return fxDatePrint4Digits(p, value);
1472
34.3k
}
1473
1474
txInteger fxDateSimilarYear(txInteger year)
1475
68.5k
{
1476
68.5k
  txInteger leap, day;
1477
68.5k
  if ((1970 <= year) && (year < 2038))
1478
21.6k
    return year;
1479
46.9k
  leap = mxIsLeapYear(year);
1480
46.9k
  year += mxYearsOffset - 1;
1481
46.9k
  day = mxYearDays(year) - mxYearDays(1970 + mxYearsOffset - 1);
1482
46.9k
  day = (day + 4) % 7;
1483
46.9k
  if (day < 0)
1484
31.5k
    day += 7; 
1485
46.9k
  return (leap) ? gxSimilarLeapYears[day] : gxSimilarCommonYears[day];
1486
68.5k
}
1487
1488
void fxDateSplit(txNumber value, txBoolean utc, txDateTime* dt)
1489
71.5k
{
1490
71.5k
  txInteger date, time, year, leap, month;
1491
71.5k
  const txInteger* monthsDays;
1492
71.5k
  date = (txInteger)c_trunc(value / mxDayMilliseconds);
1493
71.5k
  time = (txInteger)c_fmod(value, mxDayMilliseconds);
1494
71.5k
  if (time < 0) {
1495
2.96k
    date--;
1496
2.96k
    time += (txInteger)mxDayMilliseconds;
1497
2.96k
  }
1498
71.5k
  dt->offset = 0;
1499
71.5k
  dt->day = (date + 4) % 7;
1500
71.5k
  if (dt->day < 0)
1501
30.7k
    dt->day += 7; 
1502
71.5k
  dt->milliseconds = time % 1000;
1503
71.5k
  time /= 1000;
1504
71.5k
  dt->seconds = time % 60;
1505
71.5k
  time /= 60;
1506
71.5k
  dt->minutes = time % 60;
1507
71.5k
  time /= 60;
1508
71.5k
  dt->hours = time;
1509
71.5k
    date += mxYearDays(1970 + mxYearsOffset);
1510
71.5k
    year = 400 * (date / mx400YearsDays);
1511
71.5k
  date %= mx400YearsDays;
1512
71.5k
  date--;
1513
71.5k
  year += 100 * (date / mx100YearsDays);
1514
71.5k
  date %= mx100YearsDays;
1515
71.5k
  date++;
1516
71.5k
  year += 4 * (date / mx4YearsDays);
1517
71.5k
  date %= mx4YearsDays;
1518
71.5k
  date--;
1519
71.5k
  year += date / mx1YearDays;
1520
71.5k
    date %= mx1YearDays;
1521
71.5k
  year -= mxYearsOffset;
1522
71.5k
  leap = mxIsLeapYear(year);
1523
71.5k
    date += leap;
1524
71.5k
    monthsDays = leap ? gxLeapYearMonthsDays : gxCommonYearMonthsDays;
1525
427k
    for (month = 0; month < 11; month++) {
1526
423k
      if (date < monthsDays[month + 1])
1527
67.6k
        break;
1528
423k
    }
1529
71.5k
    date -= monthsDays[month];
1530
71.5k
  dt->date = date + 1;
1531
71.5k
  dt->month = month;
1532
71.5k
  dt->year = year;
1533
71.5k
  if (!utc) {
1534
37.4k
    txNumber former = value;
1535
37.4k
    txInteger similar;
1536
37.4k
    c_time_t time;
1537
37.4k
    c_tm tm;
1538
37.4k
    similar = fxDateSimilarYear(year);
1539
37.4k
    if (similar != year) {
1540
17.2k
      dt->year = similar;
1541
17.2k
      value = fxDateMerge(dt, 1);
1542
17.2k
    }
1543
37.4k
    time = (txInteger)c_floor(value / 1000.0);
1544
37.4k
    tm = *c_localtime(&time);
1545
37.4k
    dt->milliseconds = c_floor(c_fmod(value, 1000.0));
1546
37.4k
    dt->day = tm.tm_wday;
1547
37.4k
    dt->seconds = tm.tm_sec;
1548
37.4k
    dt->minutes = tm.tm_min;
1549
37.4k
    dt->hours = tm.tm_hour;
1550
37.4k
    dt->date = tm.tm_mday;
1551
37.4k
    dt->month = tm.tm_mon;
1552
37.4k
    dt->year = tm.tm_year + 1900 + year - similar;
1553
37.4k
    dt->offset = (txInteger)c_trunc((fxDateMerge(dt, 1) - former) / 60000.0);
1554
37.4k
  }
1555
71.5k
  dt->value = value;
1556
71.5k
}
1557
1558
1559
1560