Coverage Report

Created: 2026-01-09 07:15

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