AmiTimeKeeper/tz.c

298 lines
7.6 KiB
C
Raw Normal View History

2021-01-12 22:02:29 +00:00
/*-
* Copyright (c) 2017-2020 Carsten Sonne Larsen <cs@innolan.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "config.h"
#include "notify.h"
#include "global.h"
#include "message.h"
#include "ptz.h"
#include "timer.h"
#include "mem.h"
#include "tz.h"
#include <assert.h>
#include "logmod.h"
#define MODULENAME "Timezone"
/*
* 2922 is the number of days between 1.1.1970 and 1.1.1978
* (2 leap years and 6 normal)
* 2922 * 24 * 60 * 60 = 252460800
*/
#define AMIGA_OFFSET 252460800
#define SECONDSPERDAY 86400
static long unixEpochOffset = 0;
void LogTzInfo()
{
if (Timezone == NULL)
{
return;
}
if (Timezone->dst.abbreviation != NULL)
{
LogInfo("Standard Timezone is %s (UTC%s%02ld:%02ld)",
Timezone->std.abbreviation,
PosixTimezoneSignChar(&Timezone->std),
(long)Timezone->std.offset.hours,
(long)Timezone->std.offset.minutes);
LogInfo("DST Timezone is %s (UTC%s%02ld:%02ld)",
Timezone->dst.abbreviation,
PosixTimezoneSignChar(&Timezone->dst),
(long)Timezone->dst.offset.hours,
(long)Timezone->dst.offset.minutes);
}
else
{
LogInfo("Timezone is %s (UTC%s%02ld:%02ld)",
Timezone->std.abbreviation,
PosixTimezoneSignChar(&Timezone->std),
(long)Timezone->std.offset.hours,
(long)Timezone->std.offset.minutes);
}
}
void InitTimezone(void)
{
char TimezoneText[TIMEZONE_TEXT_LEN];
char *tz;
int result;
WatchFile("ENV:TZ", ATK_TZ_CHANGED);
WatchFile("ENV:TZONE", ATK_TZONE_CHANGED);
WatchFile("ENV:Sys/locale.prefs", ATK_LOCALE_CHANGED);
tz = NULL;
result = InitPosixTimezone(&tz);
switch (result)
{
case 1:
LogInfo("No TZ or TZONE variable found");
break;
case 2:
LogInfo("Found unknown TZONE variable");
LogDebug("TZONE = %s", tz);
break;
case 3:
LogInfo("Found unknown TZ variable");
LogDebug("TZ = %s", tz);
break;
case 4:
LogInfo("Found valid TZONE variable");
LogDebug("TZONE = %s", tz);
break;
case 5:
LogInfo("Found valid TZ variable");
LogDebug("TZ = %s", tz);
break;
default:
LogWarn("Unknown TZ or TZONE code");
break;
}
if (tz != NULL)
{
FreeMemSafe(tz);
}
if (result == 4 || result == 5)
{
struct timeval tv;
GetSysTime(&tv);
SetPosixTimezone(&tv);
LogTzInfo();
unixEpochOffset =
(Timezone->current.offset.sign < 0 ? +1 : -1) *
(Timezone->current.offset.hours * 60 * 60 +
Timezone->current.offset.minutes * 60 +
Timezone->current.offset.seconds);
unixEpochOffset += AMIGA_OFFSET;
GetTimezoneText(AppLocale, TimezoneText, OFFSET_IN_PARENS);
LogWarn("Current Timezone is %s", TimezoneText);
}
else
{
unixEpochOffset = AppLocale->AmigaLocale->loc_GMTOffset * 60 + AMIGA_OFFSET;
GetTimezoneText(AppLocale, TimezoneText, OFFSET_IN_PARENS);
LogWarn("Current Timezone is %s", TimezoneText);
}
InitTimezoneShift();
}
void Amiga2DateStamp(time_t *time, struct DateStamp *date)
{
long t, d, m, q;
t = *time;
d = t / SECONDSPERDAY;
m = (t - SECONDSPERDAY * d) / 60;
q = (t - SECONDSPERDAY * d - m * 60) * 60;
date->ds_Days = d;
date->ds_Minute = m;
date->ds_Tick = q;
}
void InitTimezoneShift(void)
{
struct PosixTransitionTime *transition;
struct timeval tv;
char *nextTime;
char *nextTrans;
time_t next;
ULONG now;
if (Timezone == NULL || Timezone->start.type == 0)
{
NextTransition = NULL;
return;
}
/*
{
int i;
for (i = 0; i < 138; i++)
{
transition = &Timezone->transitions[i];
next = transition->time;
Amiga2DateStamp(&next, &ds);
DateTimeString(&ds, timeString, dateString, dayString);
LogWarn("XChanging (%ld) to %s time on %s %s at %s %s",
next,
transition->isdst ? "DST" : "standard",
dayString, dateString, timeString,
transition->isdst
? Timezone->std.abbreviation
: Timezone->dst.abbreviation);
}
}
*/
GetSysTime(&tv);
now = (ULONG)(tv.tv_secs);
transition = FindNextTransition(now);
if (transition == NULL)
{
NextTransition = NULL;
return;
}
if (NextTransition != NULL)
{
FreeMemSafe(NextTransition);
}
NextTransition = transition;
next = transition->time;
nextTime = GetTimeText(AppLocale, next);
nextTrans = transition->isdst ? "DST" : "standard time";
LogWarn("Changing to %s on %s", nextTrans, nextTime);
FreeMemSafe(nextTime);
}
void CleanupTimezone(void)
{
CleanupPosixTimezone();
}
void Unix2Amiga(struct timeval *unix, struct timeval *tv)
{
assert(unix != NULL);
assert(tv != NULL);
tv->tv_secs = unix->tv_secs + AMIGA_OFFSET;
tv->tv_micro = unix->tv_micro;
}
void Utc2Local(struct timeval *utc, struct timeval *tv)
{
assert(utc != NULL);
assert(tv != NULL);
// TODO: Validate
tv->tv_secs = utc->tv_secs - (unixEpochOffset - AMIGA_OFFSET);
tv->tv_micro = utc->tv_micro;
}
void GetTimeOfDay(struct timeval *tv)
{
assert(tv != NULL);
GetSysTime(tv);
tv->tv_secs = tv->tv_secs + unixEpochOffset;
}
void GetLocalTimeOfDay(struct timeval *tv)
{
assert(tv != NULL);
GetSysTime(tv);
}
void SetTimeOfDay(const struct TimerInfo *info, const struct timeval *tv)
{
struct timeval t;
assert(tv != NULL);
t.tv_secs = tv->tv_secs - unixEpochOffset;
t.tv_micro = tv->tv_micro;
SetTime(&t);
}
void SaveTimeOfDay(const struct timeval *tv)
{
assert(tv != NULL);
WriteBattClock((long)tv->tv_secs - unixEpochOffset);
}
void DateTimeString(struct DateStamp *ds, char *time, char *date, char *day)
{
struct DateTime dt;
assert(ds != NULL);
assert(time != NULL);
assert(date != NULL);
assert(day != NULL);
dt.dat_Stamp = *ds;
dt.dat_Format = FORMAT_DOS;
dt.dat_Flags = 0;
dt.dat_StrDay = (void *)day;
dt.dat_StrDate = (void *)date;
dt.dat_StrTime = (void *)time;
DateToStr(&dt);
}