Coverage Report

Created: 2026-09-28 06:57

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