Как я могу добавить день в DateTime в указанном c часовом поясе - PullRequest
2 голосов
/ 28 января 2020

Возможно ли (достаточно просто) добавить день к дате в другом часовом поясе, чем DateTime.Local, соблюдая при этом другие правила настройки (DST и c) для этого конкретного часового пояса?

var rst = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time");
var dayInSpecificTimezone = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, rst); // Got the datetime in specified timezone
// now I would like to add a "day" to that, still observing the rules of that timezone.. something like:
var sameTimeTheDayAfterThat = dayInSpecificTimezone.AddDays(1, rst); // no such method exists

Ответы [ 2 ]

1 голос
/ 29 января 2020

Вот методы расширения, которые вы можете использовать для этого.

Во-первых, этот метод AddDays соответствует сигнатуре, о которой вы спрашивали. Он работает на DateTime значениях:

public static DateTime AddDays(this DateTime dt, double days, TimeZoneInfo tz)
{
    // If the kind is Local or Utc, convert that point in time to the given time zone
    DateTimeKind originalKind = dt.Kind;
    if (originalKind != DateTimeKind.Unspecified)
    {
        dt = TimeZoneInfo.ConvertTime(dt, tz);
    }

    // Add days with respect to the wall time only
    DateTime added = dt.AddDays(days);

    // Resolve the added value to a specific point in time
    DateTimeOffset resolved = added.ToDateTimeOffset(tz);

    // Return only the DateTime portion, but take the original kind into account
    switch (originalKind)
    {
        case DateTimeKind.Local:
            return resolved.LocalDateTime;
        case DateTimeKind.Utc:
            return resolved.UtcDateTime;
        default: // DateTimeKind.Unspecified
            return resolved.DateTime;
    }
}

Вот еще один вариант этого метода расширения. Этот работает с DateTimeOffset значениями:

public static DateTimeOffset AddDays(this DateTimeOffset dto, double days, TimeZoneInfo tz)
{
    // Make sure the input time is in the provided time zone
    dto = TimeZoneInfo.ConvertTime(dto, tz);

    // Add days with respect to the wall time only
    DateTime added = dto.DateTime.AddDays(days);

    // Resolve the added value to a specific point in time
    DateTimeOffset resolved = added.ToDateTimeOffset(tz);

    // Return the fully resolved value
    return resolved;
}

Оба вышеперечисленных метода зависят от следующего ToDateTimeOffset метода расширения (который я использовал в нескольких разных постах).

public static DateTimeOffset ToDateTimeOffset(this DateTime dt, TimeZoneInfo tz)
{
    if (dt.Kind != DateTimeKind.Unspecified)
    {
        // Handle UTC or Local kinds (regular and hidden 4th kind)
        DateTimeOffset dto = new DateTimeOffset(dt.ToUniversalTime(), TimeSpan.Zero);
        return TimeZoneInfo.ConvertTime(dto, tz);
    }

    if (tz.IsAmbiguousTime(dt))
    {
        // Prefer the daylight offset, because it comes first sequentially (1:30 ET becomes 1:30 EDT)
        TimeSpan[] offsets = tz.GetAmbiguousTimeOffsets(dt);
        TimeSpan offset = offsets[0] > offsets[1] ? offsets[0] : offsets[1];
        return new DateTimeOffset(dt, offset);
    }

    if (tz.IsInvalidTime(dt))
    {
        // Advance by the gap, and return with the daylight offset  (2:30 ET becomes 3:30 EDT)
        TimeSpan[] offsets = { tz.GetUtcOffset(dt.AddDays(-1)), tz.GetUtcOffset(dt.AddDays(1)) };
        TimeSpan gap = offsets[1] - offsets[0];
        return new DateTimeOffset(dt.Add(gap), offsets[1]);
    }

    // Simple case
    return new DateTimeOffset(dt, tz.GetUtcOffset(dt));
}

Наконец, я укажу, что есть еще один вариант: используйте библиотеку Noda Time . Это ZoneDateTime.Add метод имеет именно эту цель.

0 голосов
/ 29 января 2020

Добавление дня к объекту DateTime и отображение даты в определенном часовом поясе - это две разные вещи.

Функция DateTime.AddDays может использоваться для добавления дня (т.е. добавление 24 часов к текущей переменной). Затем вы можете отобразить эту дату в любом часовом поясе, который вы предпочитаете.

Например:

var rst = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time");
var dayInSpecificTimezone = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, rst); // Got the datetime in specified timezone

Console.WriteLine("RST datetime now is {0}", dayInSpecificTimezone);

var sameTimeTheDayAfterThat = dayInSpecificTimezone.AddDays(1);

Console.WriteLine("RST datetime in 1 day is {0}", sameTimeTheDayAfterThat);
Console.WriteLine("local datetime in 1 day is {0}", TimeZoneInfo.ConvertTime(sameTimeTheDayAfterThat, rst, TimeZoneInfo.Local));

даст результат, аналогичный:

RST datetime now is 29/01/2020 4:31:14 AM
RST datetime in 1 day is 30/01/2020 4:31:14 AM
local datetime in 1 day is 30/01/2020 1:31:14 PM
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...