Wrong day of week

Getting the days of the week the hard way, because there is no better way I try this:

var Jan1 = Gregorian.moment({:year => 2023, :month => 1, :day => 1});
for (var i = 0; i < self.DoW.size(); i++) {
	var DDD = Gregorian.info(Jan1.add(new Time.Duration(86400*i)), Time.FORMAT_MEDIUM);
	self.DoW[i] = DDD.day_of_week.substring(0,2).toUpper();
}

But DoW[0] = "SA"? My calendar says something different, so I try this:

var Jan1 = Gregorian.moment({:year => 2023, :month => 1, :day => 1, :hour => 12});
for (var i = 0; i < self.DoW.size(); i++) {
    var DDD = Gregorian.info(Jan1.add(new Time.Duration(86400*i)), Time.FORMAT_MEDIUM);
    self.DoW[i] = DDD.day_of_week.substring(0,2).toUpper();
}

Just by adding hour = 12 now I get the correct answer, DoW[0] = 'SU'. I'm pretty sure the day of the week is the same for all hours on Jan 1. Is this some time zone bug?

  • I decided to use Jan 8 because on Jan 1 if the day is one day off the date will be greater than 1 either way. Also as you pointed out a DST change around this time is unlikely so this should not impact the result. This seems easier to follow to me:

    // get days of the week
    // 1673179201 = Sunday, January 8, 2023 12:00:01 PM UTC
    var jan8 = new Time.Moment(1673179201);
    var janInfo = Gregorian.info(jan8, Time.FORMAT_MEDIUM);
    if (janInfo.day != 8) {
        jan8 = jan8.add(new Time.Duration(((janInfo.day < 8) ? 86400 : -86400)));
    }
    for (var i = 0; i < self.DoW.size(); i++) {
    	janInfo = Gregorian.info(jan8.add(new Time.Duration(86400*i)), Time.FORMAT_MEDIUM);
    	self.DoW[i] = janInfo.day_of_week.substring(0,2).toUpper();
    }
    

    I feel safe in assuming that if the day returned is not 8 then it's either 7 or 9 and not two or more days off. This works in the FR 235 sim, so this should be good for everybody.

  • Maybe this is easier?

    // get days of the week
    // 1673179201 = Sunday, January 8, 2023 12:00:01 PM UTC
    var janDay = new Time.Moment(1673179201);
    var oneDay = new Time.Duration(86400);
    for (var i = 0; i < self.DoW.size(); i++) {
    	janDay = janDay.add(oneDay);
    	var janShort = Gregorian.info(janDay, Time.FORMAT_SHORT);
    	var janMed = Gregorian.info(janDay, Time.FORMAT_MEDIUM);
    	self.DoW[janShort.day_of_week-1] = janMed.day_of_week.substring(0,2).toUpper();
    }
    

    Calls Gregorian.info twice, but less math and it doesn't matter what order the days come in.

  • That is almost exactly what I typed in my first example, although I did edit that post a lot, so maybe you didn't see it.

    var daysOfWeek = new[7];
    
    var jan1 = Gregorian.moment({:year => 2023, :month => 1, :day => 1});
    for (var i = 0; i < 7; i++) {
        var date = jan1.add(new Time.Duration(86400*i));
        var infoShort = Gregorian.info(date, Time.FORMAT_SHORT);
        var infoMedium = Gregorian.info(date, Time.FORMAT_MEDIUM);
        daysOfWeek[infoShort.day_of_week - 1] = infoMedium.day_of_week.substring(0, 2).toUpper();
    }
    System.println("daysOfWeek = " + daysOfWeek);
    // Output:
    // daysOfWeek = [SU, MO, TU, WE, TH, FR, SA]

    My second example was refined to:

    - Only call Gregorian.info with Time.FORMAT_SHORT once, instead of multiple times

    - Handle the (impractical) edge case where a day has 25 hours, by iterating 8 times instead of 7 (this would only be an issue if you chose a fixed date near a DST transition, which is not going to happen around Jan 1)

    var daysOfWeek = new[7];
    
    // any date at all would work
    var jan1 = Gregorian.moment({:year => 2000, :month => 1, :day => 1});
    var jan1_dow = Gregorian.info(jan1, Time.FORMAT_SHORT).day_of_week - 1;
    for (var i = 0; i < 8; i++) { // 8 is not a typo
        var date = jan1.add(new Time.Duration(86400*i));
        var infoMedium = Gregorian.info(date, Time.FORMAT_MEDIUM);
        daysOfWeek[(jan1_dow + i) % 7] = infoMedium.day_of_week.substring(0, 2).toUpper();
    }
    System.println("daysOfWeek = " + daysOfWeek);
    // Output:
    // daysOfWeek = [SU, MO, TU, WE, TH, FR, SA]

    Neither of my examples care about what order the days come in, since as you noticed (and as I said), day_of_week is an integer from 1 to 7 for Time.FORMAT_SHORT, so you let the code figure out how to map days as strings to days as integers.

    All they care about is retrieving the info for 7 unique days of the week, which both accomplish.

    For the first example (and your code above), the only caveat is that you have to pick a date which isn't near the end of DST in any jurisdiction.

    For the second example, you can pick literally any date you want, because the edge case of a single 25 hour day within an 8-day period is handled.

    Either way, glad you have a solution now.