Version 3 of Swatch Internet Time

Updated 2021-02-10 19:22:24 by dbohdan

Swatch Internet Time or .beat time is a decimal time format without time zones. It was introduced by the Swatch corporation to promote their "Beat" watches. Some products released around the year 2000 have integrated support for .beat time, as does the programming language PHP.

Tcl module

dbohdan 2021-02-10: The following module can convert a clock seconds timestamp to .beat time and .beat time to seconds since midnight in UTC. It also works as a command line utility to display Swatch Internet Time.

#! /usr/bin/env tclsh
# Copyright (c) 2021 D. Bohdan.
# License: MIT.

namespace eval beat {
    variable version 0.3.0

    # [catch] for Jim Tcl compatibility.
    catch {
        namespace export format scan from* to*
        namespace ensemble create
    }
}


# Epoch time in seconds -> .beats.
proc beat::format t {
    # Add an hour to go from UTC to UTC+1 (CET).
    from-cet-seconds [expr { ($t + 3600) % 86400 }]
}


# .beats -> seconds since midnight in UTC.
proc beat::scan beats {
    expr { ([to-cet-seconds $beats] - 3600) % 86400 }
}


proc beat::from-cet-seconds s {
    expr { int($s / 86.4) }
}


proc beat::to-cet-seconds beats {
    expr { round($beats * 86.4) }
}


proc beat::test {} {
    set ref {
        1000000000 115
        1100000000 523
        1200000000 930
        1300000000 337
        1400000000 745
        1500000000 152
        1600000000 560
        1700000000 967
        1800000000 375
        1900000000 782
        2000000000 189
        1612973550 717
    }

    set error {}

    dict for {timestamp expectedBeats} $ref {
        set actualBeats [format $timestamp]
        if {$expectedBeats != $actualBeats} {
            lappend error "$timestamp -> $expectedBeats (got $actualBeats)"
        }

        set actualS [scan $expectedBeats]
        set expectedS [expr { $timestamp % 86400 }]
        if {$expectedS - $actualS > 87} {
            lappend error "$expectedBeats -> $expectedS (got $actualS)"
        }
    }

    if {$error ne {}} {
        error "tests failed:\n[join $error \n]"
    }
}


proc beat::usage {} {
    puts stderr "usage: [file tail [info script]] \[(timestamp|\"test\")\]"
}


proc beat::main argv {
    switch [llength $argv] {
        0 {
            set timestamp [clock seconds]
        }
        1 {
            if {$argv eq {test}} {
                test
                exit 0
            }

            set timestamp $argv
            if {![string is integer -strict $timestamp]} {
                usage
                exit 1
            }
        }
        default {
            usage
            exit 1
        }
    }


    puts [format $timestamp]
}


# If this is the main script...
if {[info exists argv0] && ([file tail [info script]] eq [file tail $argv0])} {
    beat::main $argv
}

See also