Weird IF case

Former Member
Former Member
I am trying to figure out what I am doing wrong. I have had friends look at this and we can't figure out why the program doesn't enter the IF statement. WE believe the hour ==12 and offset < zero is satisfied.
I am guessing we are missing something stupid.

CODE:
// when do I need to switch AM / PM??
// when after the offset, the time is negative or greater than 12
// if old hour is 12, and the offset is negative
// if the old hour is 11 and the offset is positive
// switch AM and PM
Sys.println("Switch A and P? " + switchAP + "; hour: " + dTime["hour"] + "; Total Offset: " + totalOffset.toNumber().format("%d"));
if((12 == dTime["hour"] && 0 > totalOffset) || switchAP || (11 == dTime["hour"] && 0 < totalOffset) )
{
Sys.println("Switch");
dTime["AP"] = switchDayandNight(dTime["AP"]);
}


Console OUTPUT:
Start of Apply Offset
Split Time - dTime:{min=>04, sec=>12, hour=>12, AP=>A}
New Time: 6; 4; 12
Switch A and P? false; hour: 12; Total Offset: -21600 ******* after this statement I believe it should type "Switch"
End of calculate Offset: 6:04:12 AM
  • I'm not sure what it is you're trying to do, and therefore don't really see what the if statement is supposed to check for, but here's what I do for am/pm:
    var hour=time.hour;
    var AMPM="";
    if(!settings.is24Hour) {
    hour = time.hour % 12;
    hour = (hour == 0) ? 12 : hour;

    AMPM = (time.hour>11) ? "p" : "a";
    }


    "hour" has the correct hour for both 12 and 24hr modes, and "AMPM" is either empty (24hr mode), or has "a" or "p" (12 hr mode)

    0-11 (24hr mode) is 12a to 11a (12hr mode)
    12-23(24hr mode) is 12p to 11p (12hr mode)
  • Former Member
    Former Member over 9 years ago
    I'm not sure what it is you're trying to do, and therefore don't really see what the if statement is supposed to check for, but here's what I do for am/pm:
    var hour=time.hour;
    var AMPM="";
    if(!settings.is24Hour) {
    hour = time.hour % 12;
    hour = (hour == 0) ? 12 : hour;

    AMPM = (time.hour>11) ? "p" : "a";
    }


    "hour" has the correct hour for both 12 and 24hr modes, and "AMPM" is either empty (24hr mode), or has "a" or "p" (12 hr mode)

    0-11 (24hr mode) is 12a to 11a (12hr mode)
    12-23(24hr mode) is 12p to 11p (12hr mode)



    My concern is that the If statement should return true because hour == 12 and offset is negative. But it does Not go into the IF block.
    What I am doing is creating an app that displays sunrise and sunset data. The JSON call I make returns time in UTC. so I need to apply the offset. the sun sets at 12:17:05 AM UTC, but I have a 5 hour offset(-21600) since I live in Chicago. so that is 7:17:05 PM. I need to change AM to PM in this case. But it doesn't seem to go into the IF block.
    I even tried JUST having the condition I want:

    Sys.println("Switch ? " + switchAP + " hour: " + dTime["hour"] + " Total Offset: " + totalOffset);
    if (12 == dTime["hour"] && 0 > totalOffset )
    {
    Sys.println("Switch");
    dTime["AP"] = switchDayandNight(dTime["AP"]); // this is a function that switches A to P and vica-versa
    }

    Same output...
    .
    Start of Apply Offset
    Split Time - dTime:{min=>05, sec=>17, hour=>12, AP=>A}
    New Time: 6; 5; 17
    Switch ? false hour: 12 Total Offset: -21600 **** You can see Hour is 12 and offset is negative( causing program to go into IF Block.)
    ******* This should print the word "Switch" if we went into the IF statement. ********
    End of calculate Offset: 6:05:17 AM
    .
    .
    .
  • I agree that if there is a problem evaluating the expression you should determine why it is not working like you expect. It could be a bug in your code or the compiler.

    In looking at it, the first sub-expression of the if is the one that seems fishy to me...

    12 == dTime["hour"]


    To debug this, I just reduce the problem as far as possible. Given the output that you post, dTime is a Dictionary and the type of dTime["min"] is String (if it were a Number the display would show 5 instead of 05). Given that the minute value is a string, I'm assuming the hour value is also a string. So try the following code...

    var dTime = {
    "hour" => "12",
    "min" => "05",
    "sec" => "17",
    "AP" => "A"
    };

    var totalOffset = -21600;
    var switchAP = false;

    Sys.println("Switch ? " + switchAP + " hour: " + dTime["hour"] + " Total Offset: " + totalOffset);
    if (12 == dTime["hour"]) {
    Sys.println("A");
    }

    if (0 > totalOffset) {
    Sys.println("B");
    }

    if ((12 == dTime["hour"]) && (0 > totalOffset)) {
    Sys.println("C");
    }

    if (12 == dTime["hour"] && 0 > totalOffset) {
    Sys.println("D");
    }


    If you run that code, you get the following output...

    File pushed successfully
    Connection Finished
    Closing shell and port
    Found Transport: tcp
    Connecting...
    Connecting to device...
    Device Version 0.1.0
    Device id 1 name "A garmin device"
    Shell Version 0.1.0
    Switch ? false hour: 12 Total Offset: -21600
    B


    Notice that A didn't succeed? You're comparing an Number and a String, and the comparison is failing. Simple as that.

    Travis
  • What I am doing is creating an app that displays sunrise and sunset data. The JSON call I make returns time in UTC. so I need to apply the offset.

    You do not need to apply an offset if you want to display the local time. The Gregorian.info() routine will automatically apply the local timezone offset for you.

    using Toybox.Time as Time;
    using Toybox.Time.Gregorian as Gregorian;

    function test() {
    // this timestamp value is equivalent to
    //
    // 02/23/2016 @ 7:25:55pm (UTC)
    //
    // which is equivalent to the local time...
    //
    // 02/23/2016 @ 11:25:55am (US/Pacific)
    //
    // verify at http://www.unixtimestamp.com
    //
    var timestamp = 1456255555;

    // get a moment for the time
    var moment = new Time.Moment(timestamp);

    // get a broken-down representation of that timestamp
    var info = Gregorian.info(moment, Time.FORMAT_SHORT);

    // display it
    Sys.println(Lang.format("$1$-$2$-$3$ $4$:$5$:$6$", [
    info.year,
    info.month.format("%02d"),
    info.day.format("%02d"),
    info.hour.format("%02d"),
    info.min.format("%02d"),
    info.sec.format("%02d")
    ]));
    }


    The output, when run in the US/Pacific time zone, is...

    File pushed successfully
    Connection Finished
    Closing shell and port
    Found Transport: tcp
    Connecting...
    Connecting to device...
    Device Version 0.1.0
    Device id 1 name "A garmin device"
    Shell Version 0.1.0
    2016-02-23 11:25:55


    If you want to display the UTC time, you'd have to apply the offset. If you apply the offset, it doesn't make any sense to do it after getting the broken-down representation. You can do it with a simple subtraction...

    var clockTime = Sys.getClockTime();

    // this timestamp value is equivalent to
    //
    // 02/23/2016 @ 7:25:55pm (UTC)
    //
    // which is equivalent to the local time...
    //
    // 02/23/2016 @ 11:25:55am (US/Pacific)
    //
    // verify at http://www.unixtimestamp.com
    //
    var timestamp = 1456255555;

    // apply the time zone offset. the Gregorian.info() call applies an offset from
    // UTC to local time, so we apply the offset from local time to UTC to nullify
    // that.
    timestamp -= clockTime.timeZoneOffset;


    Travis
  • Former Member
    Former Member over 9 years ago
    thanks

    You do not need to apply an offset if you want to display the local time. The Gregorian.info() routine will automatically apply the local timezone offset for you.

    using Toybox.Time as Time;
    using Toybox.Time.Gregorian as Gregorian;

    function test() {
    // this timestamp value is equivalent to
    //
    // 02/23/2016 @ 7:25:55pm (UTC)
    //
    // which is equivalent to the local time...
    //
    // 02/23/2016 @ 11:25:55am (US/Pacific)
    //
    // verify at http://www.unixtimestamp.com
    //
    var timestamp = 1456255555;

    // get a moment for the time
    var moment = new Time.Moment(timestamp);

    // get a broken-down representation of that timestamp
    var info = Gregorian.info(moment, Time.FORMAT_SHORT);

    // display it
    Sys.println(Lang.format("$1$-$2$-$3$ $4$:$5$:$6$", [
    info.year,
    info.month.format("%02d"),
    info.day.format("%02d"),
    info.hour.format("%02d"),
    info.min.format("%02d"),
    info.sec.format("%02d")
    ]));
    }


    The output, when run in the US/Pacific time zone, is...

    File pushed successfully
    Connection Finished
    Closing shell and port
    Found Transport: tcp
    Connecting...
    Connecting to device...
    Device Version 0.1.0
    Device id 1 name "A garmin device"
    Shell Version 0.1.0
    2016-02-23 11:25:55


    If you want to display the UTC time, you'd have to apply the offset. If you apply the offset, it doesn't make any sense to do it after getting the broken-down representation. You can do it with a simple subtraction...

    var clockTime = Sys.getClockTime();

    // this timestamp value is equivalent to
    //
    // 02/23/2016 @ 7:25:55pm (UTC)
    //
    // which is equivalent to the local time...
    //
    // 02/23/2016 @ 11:25:55am (US/Pacific)
    //
    // verify at http://www.unixtimestamp.com
    //
    var timestamp = 1456255555;

    // apply the time zone offset. the Gregorian.info() call applies an offset from
    // UTC to local time, so we apply the offset from local time to UTC to nullify
    // that.
    timestamp -= clockTime.timeZoneOffset;


    Travis



    Thanks! I SWEAR I tried ".toNumber()" with the same results as before. This time it worked! Obviously I did something wrong before.


    I am getting the time as a String from the JSON request. Is there an easy way to convert a time string ("12:06:22 AM") to ClockTIme?
  • If possible, you should try to find a way to get it as a number. If you're stuck getting it as a broken down time, you have to parse it. I'd parse it into a seconds value (offset from midnight), and then add that to midnight for today. Something like this...

    class OutOfRangeException extends Lang.Exception
    {
    hidden var _message;

    function initialize(val, minInclusive, maxExclusive) {
    Exception.initialize();
    _message = Lang.format("Expected a value in the range [$1$, $2$), got $3$", [
    minInclusive, maxExclusive, val
    ]);
    }

    function getErrorMessage() {
    return _message;
    }
    }

    class InvalidNumberFormatException extends Lang.Exception
    {
    hidden var _message;

    function initialize(format) {
    Exception.initialize();
    _message = Lang.format("Expected a number, got '$1$'", [
    format
    ]);
    }

    function getErrorMessage() {
    return _message;
    }
    }

    class InvalidTimeFormatException extends Lang.Exception
    {
    hidden var _message;

    function initialize(format) {
    _message = Lang.format("Expected a time, got '$1$'", [
    format
    ]);
    }

    function getErrorMessage() {
    return _message;
    }
    }

    // only handles non-negative integers
    function string_to_number(string, base) {

    if (base == null) {
    base = 10;
    }
    else if (base < 2 || base > 10) {
    Sys.println("throwing out of range");
    throw new OutOfRangeException(base, 2, 10);
    }

    if (string.length() == 0) {
    Sys.println("throwing string length");
    throw new InvalidNumberFormat(string);
    }

    var value = 0;

    while (string.length() != 0) {
    var digit = string.substring(0, 1).toNumber();

    // we got a value that was out of range, stop parsing
    if (digit >= base) {
    break;
    }

    value = (value * base) + digit;

    // strip what we just examined
    string = string.substring(1, string.length());
    }

    return value;
    }

    function string_to_seconds(time) {
    // var time = "12:06:22 AM";

    var parts = [ [ ":", 12 ], [ ":", 59 ], [ " ", 59 ] ];

    var split = time;
    for (var i = 0; i < parts.size(); ++i) {
    var delim = split.find(parts[0]);
    if (delim == null) {
    throw new InvalidTimeFormatException(time);
    }

    var value = string_to_number(split.substring(0, delim), 10);
    if (value > parts[1]) {
    throw new InvalidTimeFormatException(time);
    }

    parts= value;

    split = split.substring(delim + 1, split.length());
    }

    parts[0] %= 12;

    if (split.equals("PM")) {
    parts[0] += 12;
    }

    return (parts[0] * 3600) +
    (parts[1] * 60) +
    (parts[2]);
    }
    [/code]

    Here is some test code to verify the sunny-day scenarios.

    function do_test_string_to_number(s, b, v) {
    var r = string_to_number(s, b);

    if (r != v) {
    Sys.println(Lang.format("Given $1$ in base $2$, got $3$. Expected $4$", [
    s, b, r, v
    ]));
    }
    }

    function do_test_string_to_seconds(s, v) {
    var r = string_to_seconds(s);

    if (r != v) {
    Sys.println(Lang.format("Given $1$, got $2$. Expected $3$", [
    s, r, v
    ]));
    }
    }

    function test_string_to_number()
    {
    do_test_string_to_number( "0", 2, 0);
    do_test_string_to_number( "1", 2, 1);
    do_test_string_to_number( "10", 2, 2);
    do_test_string_to_number( "11", 2, 3);
    do_test_string_to_number("100", 2, 4);
    do_test_string_to_number("101", 2, 5);
    do_test_string_to_number("110", 2, 6);
    do_test_string_to_number("111", 2, 7);

    do_test_string_to_number( "1", 8, 1);
    do_test_string_to_number( "2", 8, 2);
    do_test_string_to_number( "4", 8, 4);
    do_test_string_to_number( "7", 8, 7);
    do_test_string_to_number("01", 8, 1);
    do_test_string_to_number("02", 8, 2);
    do_test_string_to_number("04", 8, 4);
    do_test_string_to_number("07", 8, 7);
    do_test_string_to_number("10", 8, 8);
    do_test_string_to_number("11", 8, 9);
    do_test_string_to_number("12", 8, 10);
    do_test_string_to_number("22", 8, 18);

    do_test_string_to_number( "1", 10, 1);
    do_test_string_to_number( "2", 10, 2);
    do_test_string_to_number( "5", 10, 5);
    do_test_string_to_number("10", 10, 10);
    do_test_string_to_number("11", 10, 11);
    do_test_string_to_number("12", 10, 12);
    do_test_string_to_number("15", 10, 15);
    }

    function test_string_to_seconds()
    {
    do_test_string_to_seconds("12:00:00 AM", 0);
    do_test_string_to_seconds("12:00:01 AM", 1);
    do_test_string_to_seconds("12:00:02 AM", 2);
    do_test_string_to_seconds("12:00:10 AM", 10);
    do_test_string_to_seconds("12:00:20 AM", 20);

    do_test_string_to_seconds("12:01:00 AM", 60);
    do_test_string_to_seconds("12:02:00 AM", 120);
    do_test_string_to_seconds("12:10:00 AM", 600);
    do_test_string_to_seconds("12:20:00 AM", 1200);

    do_test_string_to_seconds("1:00:00 AM", 3600);
    do_test_string_to_seconds("1:00:01 AM", 3601);
    do_test_string_to_seconds("1:00:02 AM", 3602);
    do_test_string_to_seconds("1:00:10 AM", 3610);
    do_test_string_to_seconds("1:00:20 AM", 3620);

    do_test_string_to_seconds("1:01:00 AM", 3660);
    do_test_string_to_seconds("1:02:00 AM", 3720);
    do_test_string_to_seconds("1:10:00 AM", 4200);
    do_test_string_to_seconds("1:20:00 AM", 4800);

    do_test_string_to_seconds("11:59:59 AM", 43199);
    do_test_string_to_seconds("01:00:00 PM", 46800);
    }


    Now that you have the number of seconds since midnight, you just need to get a moment for that.

    var offset_from_midnight = string_to_seconds("11:59:59 AM");
    var moment = new Gregorian.today().add(new Time.Duration(seconds));