hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

leapsec.ha (2629B)


      1 // License: MPL-2.0
      2 // (c) 2021-2022 Byron Torres <b@torresjrjr.com>
      3 use bufio;
      4 use encoding::utf8;
      5 use fs;
      6 use io;
      7 use os;
      8 use strconv;
      9 use strings;
     10 
     11 // Hare uses raw leap second information when dealing with the UTC and TAI
     12 // timescales. This information is source from a standard file installed at
     13 // /usr/share/zoneinfo/leap-seconds.list, which itself is fetched from and
     14 // periodically maintained at various observatories.
     15 //
     16 // https://data.iana.org/time-zones/code/leap-seconds.list
     17 // https://www.ietf.org/timezones/data/leap-seconds.list
     18 // ftp://ftp.nist.gov/pub/time/leap-seconds.list
     19 // ftp://ftp.boulder.nist.gov/pub/time/leap-seconds.list
     20 //
     21 // This is in contrast to previous systems which rely on TZif files, which are
     22 // installed typically at /usr/share/zoneinfo, as part of the "Olson" IANA
     23 // Timezone database. These files couple timezone and leap second data.
     24 //
     25 // Depending on a system's installation, leap second information may be
     26 // deliberately left out of the TZif files, or duplicated throughout. This
     27 // design also inhibits our ambitions for dealing with multiple, dynamic
     28 // timescales. Therefore, we have decided to take an alternative approach.
     29 
     30 // The number of seconds between the years 1900 and 1970. This number is
     31 // deliberately hypothetical since timekeeping before atomic clocks was not
     32 // accurate enough to account for small changes in time.
     33 export def SECS_1900_1970: i64 = 2208988800;
     34 
     35 // The filepath of the system's leap-seconds.list file.
     36 export def UTC_LEAPSECS_FILE: str = "/usr/share/zoneinfo/leap-seconds.list";
     37 
     38 // UTC timestamps and their offsets from TAI, sourced from the system's
     39 // leap-seconds.list file.
     40 let utc_leapsecs: [](i64, i64) = [];
     41 
     42 @init fn init_utc_leapsecs() void = {
     43 	os::init_cwd();
     44 	const file = match (os::open(UTC_LEAPSECS_FILE)) {
     45 	case let file: io::file =>
     46 		yield file;
     47 	case fs::error =>
     48 		return;
     49 	};
     50 	defer io::close(file)!;
     51 	read_utc_leapsecs_file(file, &utc_leapsecs)!;
     52 };
     53 
     54 fn read_utc_leapsecs_file(
     55 	h: io::handle,
     56 	leapsecs: *[](i64, i64),
     57 ) (void | io::error | encoding::utf8::invalid) = {
     58 	for (true) {
     59 		const line = match (bufio::scanline(h)) {
     60 		case let err: io::error =>
     61 			return err;
     62 		case io::EOF =>
     63 			return;
     64 		case let line: []u8 =>
     65 			yield strings::try_fromutf8(line)?;
     66 		};
     67 		defer free(line);
     68 		if (strings::hasprefix(line, '#')) {
     69 			continue;
     70 		};
     71 		const pair = strings::splitn(line, "\t", 3);
     72 		if (len(pair) < 2) {
     73 			continue;
     74 		};
     75 		const a = strconv::stoi64(pair[0])!;
     76 		const b = strconv::stoi64(pair[1])!;
     77 		const a = a - SECS_1900_1970;
     78 		const pair = (a: i64, b: i64);
     79 		append(utc_leapsecs, pair);
     80 	};
     81 };