Avatar for stephenPspackman


Member since Oct 2021 • Last active Feb 2024
  • 5 conversations

Most recent activity

  • in Bangle.js
    Avatar for stephenPspackman

    @chroma, on the watch or elsewhere?

    @user140377, the problem is an actual timezone map is going to be O(megabytes), and while there are only ~600 reference locations (so using only tens of k you could practically present the user with a list ordered by [N/S biased] distance), I'm not sure where we can get their lat/lon other than trawling the IANA database manually—Java, for example, has chosen to strip it out.

    It turns out there's another problem: if you use setTimeZone it's possible to fake temporal objects in other timezones in userland (by subtracting the time zone offsets and then adjusting the underlying ms time by this amount, so that interactions with the time and date fields behave as expected), but you have to do all DST calculations yourself (and possibly break other code's expectations). To the contrary, if you use setDST it will get the calculations right automatically for the main zone, but it becomes impossible to manipulate times in other timezones no matter how hard you try, because there are now 60 (usually) unnamable minutes in every year!

    I've been trying to think of a way to address this other than to have a second kind of Date—one that's bound internally to a setDST packet—but I haven't had enough coffee yet.

  • in Bangle.js
    Avatar for stephenPspackman

    Hey chroma. How were you planning on identifying “home”? I've been able to think of at least four methods, each with drawbacks:

    1. explicit picking from a list, which is more challenging than it initially appears;
    2. waiting until you're in your home zone and then saying, here, this one now, which is more limiting than some might imagine (though technically savvy users could I suppose force the issue by temporarily overriding their phone's time zone selection);
    3. having a picker for over on Gadgetbridge and then pulling the results over to the watch, which involves messing a lot with GB;
    4. logging user behaviour and taking the one that's used most over an (eventually) extended period.

    The last is both the hardest and the most magical (though I note there's a security implication if your watch is seized)…

  • in Bangle.js
    Avatar for stephenPspackman

    I'll do that. Enjoy your holiday (I hope that's what's happening)!

  • in Bangle.js
    Avatar for stephenPspackman

    I see—so the GB() idiom is clearly preferred going forward, and it's acceptable, nay desired, to have time setting move there eventually. I had wondered about that, and it turns out to be the key point :).

    Oh, about the Gadgetbridge repo—if I submit Bangle-related changes over there do you get pinged to review them, or is it safest for all if I run them by you in advance on a side channel, or what? I'm not sure how they are set up.

  • in Bangle.js
    Avatar for stephenPspackman

    [TL;DR: Your idea works, Gordon, I will do your idea (plus a separate Gadgetbridge timezone service) unless the thing at the numbered points below strikes you as better.]

    Ah, I hadn't understood that setDST sidesteps the 12 parameter limit. It's documented as taking an array, but when you try it, it doesn't, it takes multiple literal arguments, and I hadn't guessed that the protocol conversion could happen under the hood, so I thought the it ws a documentation error. My ignorance, sorry.

    The respect in which I means that setDST might need “rescuing” (other than the parameter count limit I falsely imagined to affect it) is the behaviour of implicitly disabling setTimeZone, which is not merely weird, it means that almost any use of it is a breaking change for someone, and you are clearly very averse to breaking changes. If Gadgetbridge starts calling it, then setTimeZone stops working after disconnection for everyone, for example.

    But anyway, here's another idea:

    1. Give Gadgetbridge a time zone lookup service, and move the main burden to the app. This would even let people implement time zone aware alarms and calendars, for example, and would make it easier to cache your home time zone, would allow for localisation, and so on.
    2. [optional] Have Gadgetbridge routinely send six parameters to setTimeZone (most of which the current implementation will silently ignore, giving back compatibility): setTimeZone(offset, [tzID], [nextChangeInstant, nextOffset, nexttzID]). tzID here is the official identifier, not the user-facing label, giving you a key you can send to the above lookup service. The motivation for sending a single prospective transition is so that you can tolerate a few weeks of disconnection and not miss a DST change, while minimising code and space complexity on the watch.
    3. Have a library that patches in a more sophisticated setTimeZone that uses the extra parameters, for people who want it. Maybe migrate this to the interpreter later if it's seen as good.

    I suggest this not because I'm trying to argue with you—treating time updates uniformly in Gadgetbridge is attractive—but because it's a more capable variant of something you suggested yourself earlier, and I think it avoids disabling anything or changing any behaviour without anyone's consent.

    On the social side, please understand that when I said I'm not interested in other people's solutions, I wasn't trying to defend being an asshole engineer, I was trying to explain (to third parties on this thread) that telling me to make do with someone else's watch face is kind of pointless because I bought a Bangle so I could write watch faces. “Why don't you have a different hobby” is sort of a non-suggestion in a way that “why don't you propose a better/less disruptive interface” or “have you overlooked such-and-such a consideration” is not.

    And don't worry, I'm perfectly aware that I can fork the world, and that the only benefit of checking things in is to benefit others, and that you have stuff to do in your own life. Otherwise you'd have had pull requests some time ago.

    My plan now:

    I'll move the burden onto Gadgetbridge and do the time request and the timezone service approach, unless you turn out to giving setTimeZone extra args, or you tell me otherwise. It has the downside that my faces will need to disable E.setTimeZone so they can use the service instead, but as you say, that can be seen as prototyping a future, more uniform, interface.

  • in Bangle.js
    Avatar for stephenPspackman

    Hey, Gordon.

    Without disagreeing in any way that the most direct thing to do is E.setTimeZone(amt, name), I took a few more steps down the rabbit hole of looking at scheduled DST changes. It seems there are some peculiarities baked into E.setDST()? First, it already has 12 parameters(!), which means that unlike E.setTimeZone() it can't straightforwardly take optional time zone name parameters at the end. Second, to the point of not breaking existing uses, it appears from reading the code that widdst depends on the fact that setDST disables setTimeZone to prevent further host time zone updates, and thus relies on the host not calling setDST, since that would break the override.

    So … one might wish that the entry had been setDST(base, delta, startRule, endRule) where startRule and endRule are arrays, for example. And while preventing automatic updates is a sensible idea, it might be better to have said Bangle.setEnableAutomaticTimezone(false)­ explicitly, rather than accomplishing it by implicitly disabling setTimeZone.

    It seems wrong to set up a competing version of setDST, but then again it seems—if my reading of the code is correct, of course—that widdst is relying on being the sole user of the call!

    Given this, I can imagine several ways forward to ‘rescue’ on-device DST processing, each slightly ugly in its own way:

    1. Change the interface of setDST breakingly, updating any clients that use it, and split off an explicit setEnableAutomaticTimezone() entrypoint;
    2. Keep all existing entrypoints unchanged and add a new one that allows setting DST under a slightly different interface, while (like setTimeZone) being implicitly disabled by setDST;
    3. Extend setTimeZone so that it takes an optional label and optional rules to schedule changes (again while maintaining the peculiar interaction with setDST, now exactly as documented);
    4. Like (2) or (3), but adding the explicit override mechanism from (1).

    What, if anything, would you like for your baby? :) I'm a bit sad to give up prospective DST advice, but if your response is just to leave it and go with the minimal thing, I'll live. ;)

  • in Bangle.js
    Avatar for stephenPspackman

    I think I agree.

    Incidentally, although I'm confident that I saw setDST behave inconsistently with getIsDST as I described, other things later started acting strangely. I reset and reloaded my Bangle 2 and I can no longer reproduce the inconsistency—and the source seems to look right. So perhaps I had already broken something.

    Oh, thanks for the LogCat pointer. It turns out that I can use that with WiFi debugging too. It's not perfect, but it's quite nice.

  • in Bangle.js
    Avatar for stephenPspackman

    Oh, believe me, I understand completely about the difference between the issues that will realistically be addressed and … everything else :). I'll take a quick look at the setDST/isDST interaction and see if it feels like a hobbyable fix—though by design setDST is only a DST-aware version of manually setting the time, and may not even be part of a location-aware solution.

    As to the idea of mapping from offset to name, from a technical perspective this can't work fully, because there are more timezones than there are offsets: timezones can (and do) differ in whether they observe DST and in what dates they make the change on, for example, not to mention that it might be a political hot potato to tell people in Western Australia that they are in China Standard Time or vice versa. (I had originally thought of making the watch able to display the correct time when completely disconnected, but the geospatial database would be megabyte-scale according to the back of my envelope, so not really feasible on Bangle).

    For the sake of other readers I should make my own perspective clear here: I bought my Bangle because I have a long-time (if low-investment) hobby of sketching watch faces and watch features, and Bangle finally provides a low-overhead method to try out ideas. So “why don't you just use this-or-that” is not the answer for me. I'm actually trying to prototype a watch face that helps me deal with the disorientation I feel when the time changes under me, and that's what justifies my effort to myself. But of course I want to do it in a way that it might be useful to others, if there is a choice of methods, and I certainly don't want to break anything.

    More generally, I think it might need saying that the experience of timezones in North America is very different from that in Europe. US states cooperate less than European nations(!) and timezone issues are a daily fact of life here; the Central/Eastern divide in the US in particular is highly populated. It's also true that while international travel has not been much of a thing for the last five years, previously (and now, again) waking up on a different continent was very much a normal experience for some of us.

    Anyway, I'll try to avoid destabilising anything, and run anything with implications for others by you before trying to check them in.

    Incidentally, do you have a clean way of debugging Gadgetbridge/Bangle interactions? Bluetooth seems to require running on real hardware, and there's only one Bluetooth….

  • in Bangle.js
    Avatar for stephenPspackman

    Looking into doing it ‘right’, I find that E.setDST allows us to set a (single) DST rule prospectively—clearly useful if we are not connected at the moment of transition. There are problems, though:

    • Based on a quick experiment in the emulator, it apparently updates the time and the locale but is not fully integrated with Date (it seemingly does not set IsDST or update getTimezoneOffset, the latter of which is probably bad for existing code since it seemingly means that we are out of sync with UTC, the only indication being in the toString-style accessors).
    • It encodes the rules in a different way from Java's ZoneOffsetTransitionRule, and in particular doesn't seem to allow for transitions that aren't pinned to a particular day of the week (I don't know how common that is). (The documentation is also unclear on the distinction between transitions at 00:00 and at 24:00, but perhaps the behaviour is well defined and/or finessable.)
    • It doesn't provide a clear strategy for the case where a rule is changing.

    Is the apparent lack of integration here a reportable bug, the result of a change in design direction, or just me misunderstanding how it fits together?

    In light of this, and existing code, is it better to call setDST (massaging its input so that it is at least valid for the upcoming transition, if not subsequent ones) or—my original thought—to ignore it, relying entirely on connected updates (possibly scheduling the next transition for the current zone, so that having only sporadic connection would work nicely)?