Diff
Not logged in

Differences From Artifact [7df877e753]:

To Artifact [4275c9c1db]:


1540
1541
1542
1543
1544
1545
1546
1547

1548
1549

1550
1551
1552
1553
1554
1555
1556
1540
1541
1542
1543
1544
1545
1546

1547
1548

1549
1550
1551
1552
1553
1554
1555
1556







-
+

-
+







    Tcl_DictObjPut(NULL, dict, lit[LIT_TZNAME], fields.tzName);
    Tcl_DecrRefCount(fields.tzName);
    Tcl_DictObjPut(NULL, dict, lit[LIT_TZOFFSET],
	    Tcl_NewWideIntObj(fields.tzOffset));
    Tcl_DictObjPut(NULL, dict, lit[LIT_JULIANDAY],
	    Tcl_NewWideIntObj(fields.julianDay));
    Tcl_DictObjPut(NULL, dict, lit[LIT_GREGORIAN],
	    Tcl_NewWideIntObj(fields.gregorian));
	    Tcl_NewWideIntObj(!(fields.flags & CLF_BGREG)));
    Tcl_DictObjPut(NULL, dict, lit[LIT_ERA],
	    lit[fields.isBce ? LIT_BCE : LIT_CE]);
	    lit[(fields.flags & CLF_BCE) ? LIT_BCE : LIT_CE]);
    Tcl_DictObjPut(NULL, dict, lit[LIT_YEAR],
	    Tcl_NewWideIntObj(fields.year));
    Tcl_DictObjPut(NULL, dict, lit[LIT_DAYOFYEAR],
	    Tcl_NewWideIntObj(fields.dayOfYear));
    Tcl_DictObjPut(NULL, dict, lit[LIT_MONTH],
	    Tcl_NewWideIntObj(fields.month));
    Tcl_DictObjPut(NULL, dict, lit[LIT_DAYOFMONTH],
1711
1712
1713
1714
1715
1716
1717

1718




1719
1720
1721
1722
1723
1724
1725
1711
1712
1713
1714
1715
1716
1717
1718

1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729







+
-
+
+
+
+







	    || FetchIntField(interp, dict, lit[LIT_MONTH], &fields.month)
		!= TCL_OK
	    || FetchIntField(interp, dict, lit[LIT_DAYOFMONTH],
		&fields.dayOfMonth) != TCL_OK
	    || TclGetIntFromObj(interp, objv[2], &changeover) != TCL_OK) {
	return TCL_ERROR;
    }
    if (isBce) {
    fields.isBce = isBce;
	fields.flags |= CLF_BCE;
    } else {
	fields.flags &= ~CLF_BCE;
    }

    /*
     * Get Julian day.
     */

    GetJulianDayFromEraYearMonthDay(&fields, changeover);

1796
1797
1798
1799
1800
1801
1802

1803




1804
1805
1806
1807
1808
1809
1810
1800
1801
1802
1803
1804
1805
1806
1807

1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818







+
-
+
+
+
+







	    || FetchIntField(interp, dict, lit[LIT_ISO8601WEEK],
		&fields.iso8601Week) != TCL_OK
	    || FetchIntField(interp, dict, lit[LIT_DAYOFWEEK],
		&fields.dayOfWeek) != TCL_OK
	    || TclGetIntFromObj(interp, objv[2], &changeover) != TCL_OK) {
	return TCL_ERROR;
    }
    if (isBce) {
    fields.isBce = isBce;
	fields.flags |= CLF_BCE;
    } else {
	fields.flags &= ~CLF_BCE;
    }

    /*
     * Get Julian day.
     */

    GetJulianDayFromEraYearWeekDay(&fields, changeover);

2351
2352
2353
2354
2355
2356
2357
2358

2359
2360
2361
2362
2363
2364
2365
2359
2360
2361
2362
2363
2364
2365

2366
2367
2368
2369
2370
2371
2372
2373







-
+







	return TCL_ERROR;
    }

    /*
     * Fill in the date in 'fields' and use it to derive Julian Day.
     */

    fields->isBce = 0;
    fields->flags &= ~CLF_BCE;
    fields->year = timeVal->tm_year + 1900;
    fields->month = timeVal->tm_mon + 1;
    fields->dayOfMonth = timeVal->tm_mday;
    GetJulianDayFromEraYearMonthDay(fields, changeover);

    /*
     * Convert that value to seconds.
2501
2502
2503
2504
2505
2506
2507
2508

2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524

2525
2526
2527
2528
2529
2530
2531
2509
2510
2511
2512
2513
2514
2515

2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531

2532
2533
2534
2535
2536
2537
2538
2539







-
+















-
+







    /*
     * Find the given date, minus three days, plus one year. That date's
     * iso8601 year is an upper bound on the ISO8601 year of the given date.
     */

    temp.julianDay = fields->julianDay - 3;
    GetGregorianEraYearDay(&temp, changeover);
    if (temp.isBce) {
    if (temp.flags & CLF_BCE) {
	temp.iso8601Year = temp.year - 1;
    } else {
	temp.iso8601Year = temp.year + 1;
    }
    temp.iso8601Week = 1;
    temp.dayOfWeek = 1;
    GetJulianDayFromEraYearWeekDay(&temp, changeover);

    /*
     * temp.julianDay is now the start of an ISO8601 year, either the one
     * corresponding to the given date, or the one after. If we guessed high,
     * move one year earlier
     */

    if (fields->julianDay < temp.julianDay) {
	if (temp.isBce) {
	if (temp.flags & CLF_BCE) {
	    temp.iso8601Year += 1;
	} else {
	    temp.iso8601Year -= 1;
	}
	GetJulianDayFromEraYearWeekDay(&temp, changeover);
    }

2567
2568
2569
2570
2571
2572
2573
2574

2575
2576
2577
2578
2579
2580
2581
2575
2576
2577
2578
2579
2580
2581

2582
2583
2584
2585
2586
2587
2588
2589







-
+







    int n;

    if (jday >= changeover) {
	/*
	 * Gregorian calendar.
	 */

	fields->gregorian = 1;
	fields->flags &= ~CLF_BGREG;
	year = 1;

	/*
	 * n = Number of 400-year cycles since 1 January, 1 CE in the
	 * proleptic Gregorian calendar. day = remaining days.
	 */

2605
2606
2607
2608
2609
2610
2611
2612

2613
2614
2615
2616
2617
2618
2619
2613
2614
2615
2616
2617
2618
2619

2620
2621
2622
2623
2624
2625
2626
2627







-
+







	}
	year += 100 * n;
    } else {
	/*
	 * Julian calendar.
	 */

	fields->gregorian = 0;
	fields->flags |= CLF_BGREG;
	year = 1;
	day = jday - JDAY_1_JAN_1_CE_JULIAN;
    }

    /*
     * n = number of 4-year cycles; days = remaining days.
     */
2643
2644
2645
2646
2647
2648
2649
2650

2651
2652
2653

2654
2655
2656
2657
2658
2659
2660
2651
2652
2653
2654
2655
2656
2657

2658
2659
2660

2661
2662
2663
2664
2665
2666
2667
2668







-
+


-
+







    year += n;

    /*
     * store era/year/day back into fields.
     */

    if (year <= 0) {
	fields->isBce = 1;
	fields->flags |= CLF_BCE;
	fields->year = 1 - year;
    } else {
	fields->isBce = 0;
	fields->flags &= ~CLF_BCE;
	fields->year = year;
    }
    fields->dayOfYear = (int)day + 1;
}

/*
 *----------------------------------------------------------------------
2732
2733
2734
2735
2736
2737
2738
2739

2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756





2757
2758
2759
2760
2761
2762
2763
2740
2741
2742
2743
2744
2745
2746

2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776







-
+

















+
+
+
+
+








    firstWeek.tzName = NULL;

    /*
     * Find January 4 in the ISO8601 year, which will always be in week 1.
     */

    firstWeek.isBce = fields->isBce;
    firstWeek.flags = (fields->flags & CLF_BCE);
    firstWeek.year = fields->iso8601Year;
    firstWeek.month = 1;
    firstWeek.dayOfMonth = 4;
    GetJulianDayFromEraYearMonthDay(&firstWeek, changeover);

    /*
     * Find Monday of week 1.
     */

    firstMonday = WeekdayOnOrBefore(1, firstWeek.julianDay);

    /*
     * Advance to the given week and day.
     */

    fields->julianDay = firstMonday + 7 * (fields->iso8601Week - 1)
	    + fields->dayOfWeek - 1;
    if (fields->julianDay >= changeover) {
	fields->flags &= ~CLF_BGREG;
    } else {
	fields->flags |= CLF_BGREG;
    }
}

/*
 *----------------------------------------------------------------------
 *
 * GetJulianDayFromEraYearMonthDay --
 *
2777
2778
2779
2780
2781
2782
2783
2784

2785
2786
2787
2788
2789
2790
2791
2790
2791
2792
2793
2794
2795
2796

2797
2798
2799
2800
2801
2802
2803
2804







-
+







GetJulianDayFromEraYearMonthDay(
    TclDateFields *fields,	/* Date to convert */
    int changeover)		/* Gregorian transition date as a Julian Day */
{
    Tcl_WideInt ym1, ym1o4, ym1o100, ym1o400;
    int year, month, mm1, q, r;

    if (fields->isBce) {
    if (fields->flags & CLF_BCE) {
	year = 1 - fields->year;
    } else {
	year = fields->year;
    }

    /*
     * Reduce month modulo 12.
2803
2804
2805
2806
2807
2808
2809
2810

2811
2812

2813
2814
2815

2816
2817
2818
2819
2820
2821
2822
2816
2817
2818
2819
2820
2821
2822

2823
2824

2825
2826
2827

2828
2829
2830
2831
2832
2833
2834
2835







-
+

-
+


-
+







    month = r + 1;
    ym1 = year - 1;

    /*
     * Adjust the year after reducing the month.
     */

    fields->gregorian = 1;
    fields->flags &= ~CLF_BGREG;
    if (year < 1) {
	fields->isBce = 1;
	fields->flags |= CLF_BCE;
	fields->year = 1 - year;
    } else {
	fields->isBce = 0;
	fields->flags &= ~CLF_BCE;
	fields->year = year;
    }

    /*
     * Try an initial conversion in the Gregorian calendar.
     */

2854
2855
2856
2857
2858
2859
2860
2861

2862
2863
2864
2865

2866
2867
2868
2869
2870
2871
2872
2867
2868
2869
2870
2871
2872
2873

2874
2875
2876
2877

2878
2879
2880
2881
2882
2883
2884
2885







-
+



-
+








    /*
     * If the resulting date is before the Gregorian changeover, convert in
     * the Julian calendar instead.
     */

    if (fields->julianDay < changeover) {
	fields->gregorian = 0;
	fields->flags |= CLF_BGREG;
	fields->julianDay = JDAY_1_JAN_1_CE_JULIAN - 1
		+ fields->dayOfMonth
		+ daysInPriorMonths[year%4 == 0][month - 1]
		+ (365 * ym1)
		+ (ONE_YEAR * ym1)
		+ ym1o4;
    }
}

/*
 *----------------------------------------------------------------------
 *
2888
2889
2890
2891
2892
2893
2894
2895

2896
2897
2898
2899
2900
2901
2902
2903
2904

2905
2906

2907
2908

2909
2910
2911
2912
2913
2914
2915
2916

2917
2918

2919
2920

2921
2922
2923
2924
2925
2926
2927
2901
2902
2903
2904
2905
2906
2907

2908
2909
2910
2911
2912
2913
2914
2915
2916

2917
2918

2919
2920

2921
2922
2923
2924
2925
2926
2927
2928

2929
2930

2931
2932

2933
2934
2935
2936
2937
2938
2939
2940







-
+








-
+

-
+

-
+







-
+

-
+

-
+







TclGetJulianDayFromEraYearDay(
    TclDateFields *fields,	/* Date to convert */
    int changeover)		/* Gregorian transition date as a Julian Day */
{
    Tcl_WideInt year, ym1;

    /* Get absolute year number from the civil year */
    if (fields->isBce) {
    if (fields->flags & CLF_BCE) {
	year = 1 - fields->year;
    } else {
	year = fields->year;
    }

    ym1 = year - 1;

    /* Try the Gregorian calendar first. */
    fields->gregorian = 1;
    fields->flags &= ~CLF_BGREG;
    fields->julianDay =
	    1721425
	    JDAY_1_JAN_1_CE_GREGORIAN - 1
	    + fields->dayOfYear
	    + (365 * ym1)
	    + (ONE_YEAR * ym1)
	    + (ym1 / 4)
	    - (ym1 / 100)
	    + (ym1 / 400);

    /* If the date is before the Gregorian change, use the Julian calendar. */

    if (fields->julianDay < changeover) {
	fields->gregorian = 0;
	fields->flags |= CLF_BGREG;
	fields->julianDay =
		1721423
		JDAY_1_JAN_1_CE_JULIAN - 1
		+ fields->dayOfYear
		+ (365 * ym1)
		+ (ONE_YEAR * ym1)
		+ (ym1 / 4);
    }
}
/*
 *----------------------------------------------------------------------
 *
 * TclIsGregorianLeapYear --
2937
2938
2939
2940
2941
2942
2943
2944

2945
2946
2947
2948
2949


2950
2951
2952
2953
2954
2955
2956
2950
2951
2952
2953
2954
2955
2956

2957
2958
2959
2960
2961

2962
2963
2964
2965
2966
2967
2968
2969
2970







-
+




-
+
+








int
TclIsGregorianLeapYear(
    TclDateFields *fields)	/* Date to test */
{
    Tcl_WideInt year = fields->year;

    if (fields->isBce) {
    if (fields->flags & CLF_BCE) {
	year = 1 - year;
    }
    if (year % 4 != 0) {
	return 0;
    } else if (!(fields->gregorian)) {
    } else if (fields->flags & CLF_BGREG) {
	/* Before Gregorian leap year didn't follow y/100 and y/400 logic. */
	return 1;
    } else if (year % 400 == 0) {
	return 1;
    } else if (year % 100 == 0) {
	return 0;
    } else {
	return 1;
3672
3673
3674
3675
3676
3677
3678

































3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    }
    Tcl_SetObjResult(interp, Tcl_NewWideIntObj(yy.date.seconds));
    return TCL_OK;
}

/*----------------------------------------------------------------------
 *
 * ClockAssembleJulianDay --
 *
 *	Assembles julianDay using year, month, etc. Thereby it'd also update
 *	gregorian flag.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static void
ClockAssembleJulianDay(
    DateInfo *info)		/* Clock scan info structure */
{
    /* Assemble julianDay (and also gregorian flag) */
    if (info->flags & CLF_ISO8601WEEK) {
	GetJulianDayFromEraYearWeekDay(&yydate, GREGORIAN_CHANGE_DATE);
    } else if (!(info->flags & CLF_DAYOFYEAR) /* no day of year */
	    || (info->flags & (CLF_DAYOFMONTH|CLF_MONTH)) /* yymmdd over yyddd */
	    == (CLF_DAYOFMONTH|CLF_MONTH)) {
	GetJulianDayFromEraYearMonthDay(&yydate, GREGORIAN_CHANGE_DATE);
    } else {
	TclGetJulianDayFromEraYearDay(&yydate, GREGORIAN_CHANGE_DATE);
    }
    info->flags |= CLF_ASSEMBLE_SECONDS;
}

/*----------------------------------------------------------------------
 *
 * ClockScanCommit --
 *
 *	Converts date info structure into UTC seconds.
 *
 * Results:
 *	Returns a standard Tcl result.
 *
3704
3705
3706
3707
3708
3709
3710
3711
3712

3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3751
3752
3753
3754
3755
3756
3757


3758








3759
3760
3761
3762
3763
3764
3765







-
-
+
-
-
-
-
-
-
-
-







	if (ClockValidDate(info, opts, CLF_VALIDATE_S1) != TCL_OK) {
	    return TCL_ERROR;
	}
    }

    /* If needed assemble julianDay using year, month, etc. */
    if (info->flags & CLF_ASSEMBLE_JULIANDAY) {
	if (info->flags & CLF_ISO8601WEEK) {
	    GetJulianDayFromEraYearWeekDay(&yydate, GREGORIAN_CHANGE_DATE);
	ClockAssembleJulianDay(info);
	} else if (!(info->flags & CLF_DAYOFYEAR) /* no day of year */
		|| (info->flags & (CLF_DAYOFMONTH|CLF_MONTH)) /* yymmdd over yyddd */
		== (CLF_DAYOFMONTH|CLF_MONTH)) {
	    GetJulianDayFromEraYearMonthDay(&yydate, GREGORIAN_CHANGE_DATE);
	} else {
	    TclGetJulianDayFromEraYearDay(&yydate, GREGORIAN_CHANGE_DATE);
	}
	info->flags |= CLF_ASSEMBLE_SECONDS;
	info->flags &= ~CLF_ASSEMBLE_JULIANDAY;
    }

    /* some overflow checks */
    if (info->flags & CLF_JULIANDAY) {
	double curJDN = (double)yydate.julianDay
		+ ((double)yySecondOfDay - SECONDS_PER_DAY/2) / SECONDS_PER_DAY;
3833
3834
3835
3836
3837
3838
3839








3840
3841
3842
3843
3844
3845
3846
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892







+
+
+
+
+
+
+
+







    if (info->flags & CLF_MONTH) {
	if (yyMonth < 1 || yyMonth > 12) {
	    errMsg = "invalid month";
	    errCode = "month";
	    goto error;
	}
    }

    /* To check day in leap year correct, validation may need gregorian flag,
     * so assemble julianDay and gregorian flag from date tokens. */
    if (info->flags & CLF_ASSEMBLE_JULIANDAY) {
	ClockAssembleJulianDay(info);
	info->flags &= ~CLF_ASSEMBLE_JULIANDAY;
    }

    /* day of month */
    if (info->flags & (CLF_DAYOFMONTH|CLF_DAYOFWEEK)) {
	if (yyDay < 1 || yyDay > 31) {
	    errMsg = "invalid day";
	    errCode = "day";
	    goto error;
	}
4017
4018
4019
4020
4021
4022
4023
4024

4025
4026
4027
4028
4029
4030
4031
4063
4064
4065
4066
4067
4068
4069

4070
4071
4072
4073
4074
4075
4076
4077







-
+







    if (info->flags & CLF_YEAR) {
	if (yyYear < 100) {
	    if (yyYear >= dataPtr->yearOfCenturySwitch) {
		yyYear -= 100;
	    }
	    yyYear += dataPtr->currentYearCentury;
	}
	yydate.isBce = 0;
	yydate.flags &= ~CLF_BCE;
	info->flags |= CLF_ASSEMBLE_JULIANDAY|CLF_ASSEMBLE_SECONDS;
    }

    /*
     * If the caller supplied a time zone in the string, make it into a time
     * zone indicator of +-hhmm and setup this time zone.
     */
4234
4235
4236
4237
4238
4239
4240
4241

4242
4243
4244
4245
4246
4247
4248
4280
4281
4282
4283
4284
4285
4286

4287
4288
4289
4290
4291
4292
4293
4294







-
+








	/* if needed assemble julianDay now */
	if (info->flags & CLF_ASSEMBLE_JULIANDAY) {
	    GetJulianDayFromEraYearMonthDay(&yydate, GREGORIAN_CHANGE_DATE);
	    info->flags &= ~CLF_ASSEMBLE_JULIANDAY;
	}

	yydate.isBce = 0;
	yydate.flags &= ~CLF_BCE;
	yydate.julianDay = WeekdayOnOrBefore(yyDayOfWeek, yydate.julianDay + 6)
		+ 7 * yyDayOrdinal;
	if (yyDayOrdinal > 0) {
	    yydate.julianDay -= 7;
	}
	info->flags |= CLF_ASSEMBLE_DATE|CLF_ASSEMBLE_SECONDS;
    }