Gregorian.info - is it null safe or anything else to consider if used?

I have following code:

var infoShort = Gregorian.info(Time.now(), Time.FORMAT_SHORT);
var day = infoShort.day;
var dayOfWeek = infoShort.day_of_week; // 1 = Sunday, 2 = Monday, ..., 7 = Saturday
var month = infoShort.month; //1 = January, 2= February, ..., 12 = December
var year = infoShort.year;

I get same Invalid value and System error crashes when using the data above... E.g. I see 160 Invalid value crash errors for following line:

var resDays = [
	Rez.Strings.Sun,
	Rez.Strings.Mon,
	Rez.Strings.Tue,
	Rez.Strings.Wed,
	Rez.Strings.Thu,
	Rez.Strings.Fri,
	Rez.Strings.Sat
];
var weekdayName = WatchUi.loadResource(resDays[dayOfWeek - 1]); // <= crashes sometimes

I think assuming that dayOfWeek is in the range [1, 7] as documented here (https://developer.garmin.com/connect-iq/api-docs/Toybox/Time/Gregorian.html) should be save, but why do I get the above exception then?

  • I think he means the integers from 1 to 7 that you get for day_of_week when you use Time.FORMAT_SHORT.

  • I see, than he's doing the same as I do as well already

  • In the sim, you can use time Simulation under settings to cycle time and days.  It's also a good way to make sure 24/7 time works/fits in 12/24 hour mode.

  • I was looking for something to set the time - did find it now, thanks for the tipp.

    Regarding the problem, will following exceptions error show up in ERA?

    if (dayOfWeek == null || dayOfWeek < 1 || dayOfWeek > 7) {
    	throw new Lang.InvalidValueException("dayOfWeek not in range [1, 7]");
    }

  • Since this rarely happens, what I'd consider doing is displaying something on the watch itself.

    if(dayOfWeek==null) {dayName="nul";}

    else if(davOfWeek<1 || dayOfWeek>7) {dayName="D+dayOfWeek;}

    else {dayName=days[dayOfWeek-1];}

    and then display it.  You'll hear from a user reporting an odd day name, and add something in the description asking for such reports.

  • Regarding the problem, will following exceptions error show up in ERA?

    That's a good idea -- using an exception like this is equivalent to the idea about runtime assertions, except I would tweak it to display the actual value of dayOfWeek:

    var dayOfWeek = null;
    if (!(dayOfWeek instanceof Lang.Number) || dayOfWeek < 1 || dayOfWeek > 7) {
        throw new Lang.InvalidValueException(
    "dayOfWeek\n" +
    "  Expected: Number between 1 and 7\n" + 
    "  Actual: " + dayOfWeek);
    }

    You can even build your own run-time assertion library which does this kind of thing generically. (Embarrassed that I didn't think of using exceptions this way right off the bat -- in my defense it was 5 AM for me >_>)

    You should see an error report like this:

    Error: Unhandled Exception
    Exception: dayOfWeek
      Expected: Number between 1 and 7
      Actual: null
    Stack: 
      - compute() at ...

    You can always test this out with a beta app in the store, to make sure that the full exception text is sent in the ERA report. (I don't see why it wouldn't be.)

  • What I finally did not is following:

    • added a few checks that throw exceptions - I want the app to crash, it's faster than waiting for users telling me that they see an unknown error code
    • this lead to the new error line pointing to a switch
    • I wrapped the switch inside a try/catch
    • Error Name: Invalid Value is not catched by try/catch

    Isn't Error Name: Invalid Value an exception?

    Code looks like following now:

    // 1) check some variables...
    if (dayOfWeek == null) {
    	throw new Lang.InvalidValueException("dayOfWeek is null");
    }
    if (dayOfWeek < 1 || dayOfWeek > 7) {
    	throw new Lang.InvalidValueException("dayOfWeek not in range [1, 7]");
    }
    // ...
    
    // 2) wrap switch in try/catch
    
    try {
    	switch (field - 200) {
    		// ... a few case statements ...
    		default:
    			break;
    	}
    } catch (e) {
    	var msg = e.getErrorMessage();
    	// add variable values to msg:
    	msg += "\nfield: " + field;
    	msg += "\nyear: " + year;
    	msg += "\nmonth: " + month;
    	msg += "\nhour: " + hour;
    	msg += "\nmin: " + min;
    	// ... 
    	// rethrow wrapping new exception
    	throw new Lang.InvalidValueException(msg);
    }

    With the result, that I still get following ERA exception:

    Error Name: Invalid Value at line 13 (number adjusted to fit to the code snipplet above)

    Any ideas how I can further debug this in my release build?

  • Nope, as you've found, certain errors are not exceptions (because they're too low-level, I guess.) This includes "Invalid Value", "Array out of Bounds" and others.

    The only thing you can do is code run-time assertions which throw exceptions as discussed above. If you expect `field` on line 13 to be an instance of Number, then encode that as an assertion. Basically you need to throw your exception *before* a low level error such as Invalid Value is triggered.

  • Just out of curiosity, is that error at line 13 reproducible in the sim, too?

  • Just out of curiosity, is that error at line 13 reproducible in the sim, too?

    No. Works fine on the SIM and on my own device...

    And I am sure field is a number, because I'm calling it from another switch like following:

    case 200 + DATETIME_TIME:
    case 200 + DATETIME_WEEKDAY_AND_DAY:
    // ...
    	loadDatetime(setup, field);
    	break;

    As you can see, field inside loadDatetime (the function the code from my question is inside) can only get values being a number (field is used in the outer switch as well)...

    I will add an "field instanceof Lang.Number" check and check if I still get the same error...