天然氣日定義為 24 小時的時間范圍,從歐洲標準時間 5:00 UTC 開始,到次日 5:00 UTC 結束。在歐洲夏令時期間,它從 4:00 UTC 開始,到次日 4:00 UTC 結束(參見Wikipedia或ACER以獲取英文解釋)。
我需要在應用程式中使用 gas days 才能執行以下操作:
- 獲取任何給定 UTC 時間戳的當前 gas day。示例:“2022-03-22 05:00:00”(UTC)應變為“2022-03-22 00:00:00”(加油日)。
- 從特定的 gas 日添加和/或減去時間跨度(天、小時等)以獲得新的時間戳,該時間戳也將 DST 考慮在內。例如,這意味著如果我從時間戳“2022-03-29 04:00:00”(UTC)(等于煤氣日“2022-03-29)中減去 7 天,我想得到時間戳” 2022-03-22 05:00:00" (UTC)。
對我來說,這感覺好像“加油日”應該作為類似于時區的東西提供,然后我可以在我的應用程式中使用它,但是嘗試使用DateTime或DateTimeOffset讓我完全不知道我應該做什么這項作業。
誰能指出我必須做的正確方向,以允許我進行上面解釋的計算?是否有一個圖書館可以讓這更容易做?例如,我已經研究過NodaTime,但我在它的檔案中找不到任何能讓我更容易解決這個任務的東西。
uj5u.com熱心網友回復:
我將使用更精確的定義:“加油日”(或者更確切地說“加油時間”,因為這里有一個時間部分)基于德國的當地時區,但偏移了 6 個小時,使得德國的 06:00 為 00:燃氣時間為 00。
正如您在自己的實驗中發現的那樣,自定義時區方法并不那么容易實作,因為轉換都發生在德國的本地日期和時間,即使氣體轉換將值推到不同的日期也是如此。(使用 NodaTime 可能可行,但不能使用TimeZoneInfo.)
考慮到這一點,您需要在德國時間進行所有轉換和操作,然后將它們轉換為 Gas Time。一些擴展方法在這里很有用。解釋性注釋內嵌在代碼中。
public static class GasTimeExtensions
{
private static readonly TimeZoneInfo GermanyTimeZone =
TimeZoneInfo.FindSystemTimeZoneById("Europe/Berlin");
// (use "W. Europe Standard Time" for .NET < 6 on Windows)
private static readonly TimeSpan GasTimeOffset = TimeSpan.FromHours(6);
/// <summary>
/// Adjusts the provided <paramref name="dateTimeOffset"/> to Gas Time.
/// </summary>
/// <param name="dateTimeOffset">The value to adjust.</param>
/// <returns>The adjusted value.</returns>
public static DateTimeOffset AsGasTime(this DateTimeOffset dateTimeOffset)
{
// Convert to Germany's local time.
var germanyTime = TimeZoneInfo.ConvertTime(dateTimeOffset, GermanyTimeZone);
// Shift for Gas Time.
return germanyTime.ToOffset(germanyTime.Offset - GasTimeOffset);
}
/// <summary>
/// Adjusts the provided <paramref name="dateTime"/> to Gas Time.
/// </summary>
/// <param name="dateTime">The value to adjust.</param>
/// <returns>The adjusted value.</returns>
public static DateTime AsGasTime(this DateTime dateTime)
{
// Always go through a DateTimeOffset to ensure conversions and adjustments are applied.
return dateTime.ToGasDateTimeOffset().DateTime;
}
/// <summary>
/// Adjusts the provided <paramref name="dateTime"/> to Gas Time,
/// and returns the result as a <see cref="DateTimeOffset"/>.
/// </summary>
/// <param name="dateTime">The value to adjust.</param>
/// <returns>The adjusted value as a <see cref="DateTimeOffset"/>.</returns>
public static DateTimeOffset ToGasDateTimeOffset(this DateTime dateTime)
{
if (dateTime.Kind != DateTimeKind.Unspecified)
{
// UTC and Local kinds will get their correct offset in the DTO constructor.
return new DateTimeOffset(dateTime).AsGasTime();
}
// Treat the incoming value as already in gas time - we just need the offset applied.
// However, we also need to account for values that might be during DST transitions.
var germanyDateTime = dateTime GasTimeOffset;
if (GermanyTimeZone.IsInvalidTime(germanyDateTime))
{
// In the DST spring-forward gap, advance the clock forward.
// This should only happen if the data was bad to begin with.
germanyDateTime = germanyDateTime.AddHours(1);
}
// In the DST fall-back overlap, choose the offset of the *first* occurence,
// which is the same as the offset before the transition.
// Otherwise, we're not in a transition, just get the offset.
var germanyOffset = GermanyTimeZone.GetUtcOffset(
GermanyTimeZone.IsAmbiguousTime(germanyDateTime)
? germanyDateTime.AddHours(-1)
: germanyDateTime);
// Construct the Germany DTO, shift to gas time, and return.
var germanyDateTimeOffset = new DateTimeOffset(germanyDateTime, germanyOffset);
return germanyDateTimeOffset.ToOffset(germanyOffset - GasTimeOffset);
}
/// <summary>
/// Add a number of calendar days to the provided <paramref name="dateTimeOffset"/>, with respect to Gas Time.
/// </summary>
/// <remarks>
/// A day in Gas Time is not necessarily 24 hours, because some days may contain a German DST transition.
/// </remarks>
/// <param name="dateTimeOffset">The value to add to.</param>
/// <param name="daysToAdd">The number of calendar days to add.</param>
/// <returns>The result of the operation, as a <see cref="DateTimeOffset"/> in Gas Time.</returns>
public static DateTimeOffset AddGasDays(this DateTimeOffset dateTimeOffset, int daysToAdd)
{
// Add calendar days (with respect to gas time) - not necessarily 24 hours.
return dateTimeOffset.AsGasTime().DateTime.AddDays(daysToAdd).ToGasDateTimeOffset();
}
/// <summary>
/// Add a number of calendar days to the provided <paramref name="dateTime"/>, with respect to Gas Time.
/// </summary>
/// <remarks>
/// A day in Gas Time is not necessarily 24 hours, because some days may contain a German DST transition.
/// </remarks>
/// <param name="dateTime">The value to add to.</param>
/// <param name="daysToAdd">The number of calendar days to add.</param>
/// <returns>The result of the operation, as a <see cref="DateTime"/> in Gas Time.</returns>
public static DateTime AddGasDays(this DateTime dateTime, int daysToAdd)
{
// Add calendar days (with respect to gas time) - not necessarily 24 hours.
return dateTime.AsGasTime().AddDays(daysToAdd).AsGasTime();
}
}
一些使用示例:
轉換特定時間戳
var test = DateTimeOffset.Parse("2022-03-22T05:00:00Z").AsGasTime(); Console.WriteLine($"{test:yyyy-MM-ddTHH:mm:sszzz} in Gas Time is {test.UtcDateTime:yyyy-MM-ddTHH:mm:ssZ} UTC.");輸出:
2022-03-22T00:00:00-05:00 in Gas Time is 2022-03-22T05:00:00Z UTC.獲取當前氣體時間戳
var now = DateTimeOffset.UtcNow.AsGasTime(); Console.WriteLine($"It is now {now:yyyy-MM-ddTHH:mm:sszzz} in Gas Time ({now.UtcDateTime:yyyy-MM-ddTHH:mm:ssZ} UTC).");輸出:
It is now 2022-05-10T14:31:56-04:00 in Gas Time (2022-05-10T18:31:56Z UTC).添加絕對時間(小時、分鐘、秒等)
var start = DateTimeOffset.Parse("2022-03-26T05:00:00Z").AsGasTime(); var end = start.AddHours(24 * 7).AsGasTime(); // add and correct any offset change Console.WriteLine($"Starting at {start:yyyy-MM-ddTHH:mm:sszzz} Gas Time ({start.UtcDateTime:yyyy-MM-ddTHH:mm:ssZ} UTC),"); Console.WriteLine($"7 x 24hr intervals later is {end:yyyy-MM-ddTHH:mm:sszzz} Gas Time ({end.UtcDateTime:yyyy-MM-ddTHH:mm:ssZ} UTC).");輸出:
Starting at 2022-03-26T00:00:00-05:00 Gas Time (2022-03-26T05:00:00Z UTC), 7 x 24hr intervals later is 2022-04-02T01:00:00-04:00 Gas Time (2022-04-02T05:00:00Z UTC).添加或減去日歷天數(由于 DST 轉換,并非嚴格的 24 小時天數)
var start = DateTimeOffset.Parse("2022-03-26T05:00:00Z").AsGasTime(); var end = start.AddGasDays(7); // add and correct any offset change Console.WriteLine($"Starting at {start:yyyy-MM-ddTHH:mm:sszzz} Gas Time ({start.UtcDateTime:yyyy-MM-ddTHH:mm:ssZ} UTC),"); Console.WriteLine($"7 calendar days later is {end:yyyy-MM-ddTHH:mm:sszzz} Gas Time ({end.UtcDateTime:yyyy-MM-ddTHH:mm:ssZ} UTC).");輸出:
Starting at 2022-03-26T00:00:00-05:00 Gas Time (2022-03-26T05:00:00Z UTC), 7 calendar days later is 2022-04-02T00:00:00-04:00 Gas Time (2022-04-02T04:00:00Z UTC).
請注意,在最后兩個示例中,我選擇了與您不同的日期,以演示跨越 DST 過渡。
uj5u.com熱心網友回復:
您可以創建一個符合 Gas Day 規則的自定義時區。
由于您提到的規則是基于另一個時區的,因此很容易引入另一個時區的規則,并以此為基礎:
static TimeZoneInfo CreateGasDayTimezone()
{
// Use CET adjustment rules for daylight saving time
var cet = TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time");
var cetAdjustmentRules = cet.GetAdjustmentRules();
// Create a new timezone offset by 5 hours off UTC, using CET for DST
var gasday = TimeZoneInfo.CreateCustomTimeZone(
"Europe/Gas_Day",
TimeSpan.FromHours(-5),
"Gas Day",
"Gas Day (Standard)",
"Gas Day (Daylight)",
cetAdjustmentRules);
return gasday;
}
使用新時區非常簡單:
var date = new DateTime(2020, 1, 1);
var gasdayZone = CreateGasDayTimezone();
var dateAsGasDay = TimeZoneInfo.ConvertTimeFromUtc(date, gasdayZone);
Console.WriteLine(date " is " dateAsGasDay " in gas day");
uj5u.com熱心網友回復:
這是一個快速解決方案,可將您的加油日邏輯實作為附加到該System.DateTime型別的 C# 擴展方法。DateTimeOffset如果您想使用該型別,也可以將其附加到類似的邏輯。
這是代碼:
public static class SpecialDateExtensions
{
public static DateTime GetGasDay(this DateTime current)
{
var datePart = current.Date;
var gasDayThreshold = datePart.AddHours(5);
return current > gasDayThreshold ? datePart : datePart.AddDays(-1);
}
}
static void Main(string[] args)
{
// usage
var now = DateTime.Now;
var gasday = now.GetGasDay();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/472632.html
