298 lines
7.6 KiB
C
298 lines
7.6 KiB
C
|
/*-
|
||
|
* 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);
|
||
|
}
|