如何使用.NET获得当前季节? (夏天,冬天等......)

时间:2009-10-16 18:18:11

标签: c# datetime

有没有办法在给定日期的情况下找回一年中的季节?对于地球上的任何地方?

这是基于时区还是半球?

请注意,在南半球,夏季仍处于温暖的月份。

修改

澄清一下,我说的是天文seasons

10 个答案:

答案 0 :(得分:11)

您可以使用以下简单代码:

private int getSeason(DateTime date) {
    float value = (float)date.Month + date.Day / 100;   // <month>.<day(2 digit)>
    if (value < 3.21 || value >= 12.22) return 3;   // Winter
    if (value < 6.21) return 0; // Spring
    if (value < 9.23) return 1; // Summer
    return 2;   // Autumn
}

为了包括南半球的季节,代码可以成为:

private int getSeason(DateTime date, bool ofSouthernHemisphere) {
    int hemisphereConst = (ofSouthernHemisphere ? 2 : 0);
    Func<int, int> getReturn = (northern) => {
        return (northern + hemisphereConst) % 4;
    };
    float value = (float)date.Month + date.Day / 100f;  // <month>.<day(2 digit)>
    if (value < 3.21 || value >= 12.22) return getReturn(3);    // 3: Winter
    if (value < 6.21) return getReturn(0);  // 0: Spring
    if (value < 9.23) return getReturn(1);  // 1: Summer
    return getReturn(2);    // 2: Autumn
}

答案 1 :(得分:4)

答案取决于您想要如何定义每个季节。此图表Wikipedia显示每年的确切日期和时间略有变化。

一个可能“足够好”的简单解决方案是使用四个固定日期,例如:3月20日,21日至6月,22日至9月和12月21日。

答案 2 :(得分:2)

我不认为这是标准化的。这也不是众所周知的全球化数据集的一部分。

答案 3 :(得分:2)

其他人可以为您快速拨打代码,但是从您引用的Wikipedia.org article我们就知道了:

  

温带地区

     

我们可以清楚地区分六种   季节。这里列出的日期是为了   北半球:[引证需要]

* Prevernal (1 March–1 May)
* Vernal (1 May–15 June)
* Estival (15 June–15 August)
* Serotinal (15 August–15 September)
* Autumnal (15 September–1 November)
* Hibernal (1 November–1 March)

然后,您可以编写GetTemperateSeason()函数,根据月份范围返回上面的枚举。

答案 4 :(得分:2)

public class Season
{
    private const string WINTER = "Winter";
    private const string SPRING = "Spring";
    private const string SUMMER = "Summer";
    private const string AUTUMN = "Autumn";

    public string Name { get; set; }
    public string Value { get; set; }

    public List<Season> LastFiveBillingQuarters
    {
        get
        {
            IList<Season> billingPeriods = new List<Season>();
            StringBuilder sbDisplayText;
            DateTime billingPeriod;

            for (int i = 0; i >= -12; i -= 3)
            {
                billingPeriod = DateTime.Now.AddMonths(i);
                var month = billingPeriod.Month;
                var day = billingPeriod.Day;
                var year = billingPeriod.Year;
                var ticks = billingPeriod.ToString();

                sbDisplayText = new StringBuilder();

                if ((month >= 12 || month < 03) & day >= 22)
                    sbDisplayText.Append(WINTER);
                else if (month >= 09 & day >= 23)
                    sbDisplayText.Append(AUTUMN);
                else if (month >= 06 & day >= 21)
                    sbDisplayText.Append(SUMMER);
                else if (month >= 03 & day >= 21)
                    sbDisplayText.Append(SPRING);

                sbDisplayText.Append(string.Format("{0}{1}", " ", year));

                billingPeriods.Add(new Season() { Name = sbDisplayText.ToString(), Value = ticks });
            }

            return billingPeriods.ToList();
        }
    }
}

答案 5 :(得分:1)

有些晚(并且仅使用北半球),但是如果其他人在此问题上遇到绊脚石并想要更精确的近似值,则可以使用以下方法:

private int getSeason(DateTime date)
    {
        bool lastYearIsLeap = DateTime.IsLeapYear(date.Year-1);
        bool thisIsLeap = DateTime.IsLeapYear(date.Year);
        bool nextYearIsLeap = DateTime.IsLeapYear(date.Year+1);

        float summerStart = 6.21f;
        float autumnStart = 9.23f;
        float winterStart = 12.21f;

        //check if we need summer adjustment
        if (thisIsLeap)
        {
            summerStart = 6.20f;
        }
        //check if we need autumn adjustment
        if (thisIsLeap || lastYearIsLeap)
        {
            autumnStart = 9.22f;
        }
        //check if we need winter adjustment
        if (nextYearIsLeap)
        {
            winterStart = 12.22f;
        }

        if (date.Year == 2034 || date.Year == 2038)
            autumnStart -= 0.01f;

        float value = (float)date.Month + date.Day / 100f;   // <month>.<day(2 digit)>
        if (value < 3.20 || value >= winterStart) return 3;   // Winter
        if (value < summerStart) return 0; // Spring
        if (value < autumnStart) return 1; // Summer
        return 2;   // Autumn



    }

这是正确的,直到2041年。(本来可以精确到2034年,但是硬编码了2034年和2038年的修复程序...假设http://www.paolociraci.it/meteo/equinozio-solstizio.htm是正确的。

一种辅助方法,可用于检查日期(本例中为2010 -2050年

 public static string PrintSeasons()
    {
        DateTime checkDateTime = new DateTime(2010, 1, 1);
        DateTime stopDateTime = new DateTime(2050, 1, 1);

        List<KeyValuePair<string, DateTime>> Seasons = new List<KeyValuePair<string, DateTime>>();

        while (checkDateTime < stopDateTime)
        {
            DateTime switchTime = checkDateTime;
            switch (getSeason(switchTime))
            {
                case 0: //Spring
                    if (switchTime.Month == 3 && switchTime.Day > 18 && switchTime.Day < 22)
                    {
                        KeyValuePair<string, DateTime> seasonEntry = new KeyValuePair<string, DateTime>("Spring", switchTime);
                        if (!Seasons.Any(o => o.Key == "Spring" && o.Value.Year == seasonEntry.Value.Year))
                            Seasons.Add(seasonEntry);
                    }
                    break;

                case 1: //Summer
                    if (switchTime.Month == 6 && switchTime.Day > 19 && switchTime.Day < 22)
                    {
                        KeyValuePair<string, DateTime> seasonEntry = new KeyValuePair<string, DateTime>("Summer", switchTime);
                        if (!Seasons.Any(o => o.Key == "Summer" && o.Value.Year == seasonEntry.Value.Year))
                            Seasons.Add(seasonEntry);
                    }
                    break;
                case 2: //Autumn
                    if (switchTime.Month == 9 && switchTime.Day >= 19 && switchTime.Day < 25)
                    {
                        KeyValuePair<string, DateTime> seasonEntry = new KeyValuePair<string, DateTime>("Autumn", switchTime);
                        if (!Seasons.Any(o => o.Key == "Autumn" && o.Value.Year == seasonEntry.Value.Year))
                            Seasons.Add(seasonEntry);
                    }
                    break;
                case 3: //Winter
                    if (switchTime.Month == 12 && switchTime.Day > 19 && switchTime.Day < 23)
                    {
                        KeyValuePair<string, DateTime> seasonEntry = new KeyValuePair<string, DateTime>("Winter", switchTime);
                        if (!Seasons.Any(o => o.Key == "Winter" && o.Value.Year == seasonEntry.Value.Year))
                            Seasons.Add(seasonEntry);
                    }
                    break;
            }

            checkDateTime = checkDateTime.AddDays(1);
        }

        DateTime currentYear = new DateTime(2000, 1, 1);
        string test = currentYear.Year + " | ";
        foreach (var season in Seasons)
        {
            if (currentYear.Year != season.Value.Year)
            {
                test += Environment.NewLine + season.Value.Year + " | ";
                currentYear = season.Value;
            }
            test += season.Key + ": " + season.Value.ToString("dd") + " | ";
        }

        return test;
    }

答案 6 :(得分:0)

就个人而言,除非是直接要求,否则我会按季度而不是一年中的气候/时段来描述不同的部分。

答案 7 :(得分:0)

北方/南方:

21/03 - 春/秋的开始

21/06 - 夏季/冬季开始

23/09 - 秋/春的开始

22/12 - 冬/夏的开始

有时会被提前一两天,但为此您需要查看以下网站:timeanddate.com

答案 8 :(得分:0)

Asp.net内置PersianCalendar中的System.Globalization,您可以使用它轻松获取季节。

在波斯日历中:

  • 第1到3个月= 春季
  • 4到6个月= 夏季
  • 7到9个月= 秋天
  • 10到12个月= 冬季
enum Season
{
    Sprint = 1,
    Summer = 2,
    Autumn = 3,
    Winter = 4
};


var persianMonth = new PersianCalendar().GetMonth( DateTime.Now );

var season = (Season) Math.Ceiling( persianMonth / 3.0 )

答案 9 :(得分:0)

我需要一种更灵活的方法。我的季节存储在数据库中,所以我不能只比较日/月。

但是,如果您尝试考虑将一个季节的开始/结束日期与特定日期进行比较的方程式,这并不像看起来那样容易,因为新年总是会咬住您的脖子。为了解决这个问题,我决定将跨新年的季节分为两个单独的季节。然后,您可以轻松地将天/月与数学逻辑进行比较,并确定正确的季节。

使用C#方法

public class SeasonChecker
{
    public SeasonChecker()
    {
    }

    public Task<TSeason> FindSeasonAsync<TSeason>(IEnumerable<TSeason> seasons, DateTime date) where TSeason : class, ISeason
    {
        var result = seasons
            .Select(s =>
            {
                // Find season that crosses newyear
                if (s.Start.Year == s.End.Year)
                {
                    return new[] {
                        new {
                            OriginalSeason = s,
                            // Remap the season to the year 2000
                            ProcessableSeason = new InternalSeason {
                                Name = s.Name,
                                Start = new DateTime(2000, s.Start.Month, s.Start.Day),
                                End = new DateTime(2000, s.End.Month, s.End.Day)
                            }
                        }
                    };
                }
                else
                {
                    // If the season crosses the newyear, split the season
                    return new[] {
                        new {
                            OriginalSeason = s,
                            // Remap the season to the year 2000
                            ProcessableSeason = new InternalSeason {
                                Name = s.Name,
                                Start = new DateTime(2000, s.Start.Month, s.Start.Day),
                                End = new DateTime(2000, 12, 31)
                            }
                        },
                        new {
                            OriginalSeason = s,
                            // Remap the season to the year 2000
                            ProcessableSeason = new InternalSeason {
                                Name = s.Name,
                                Start = new DateTime(2000, 1, 1),
                                End = new DateTime(2000, s.End.Month, s.End.Day)
                            }
                        }
                    };
                }
            })
            .SelectMany(s => s)
            .FirstOrDefault(s =>
                // Now we can easily compare the dates.
                DateTime.Compare(s.ProcessableSeason.Start, new DateTime(2000, date.Month, date.Day)) <= 0 &&
                DateTime.Compare(new DateTime(2000, date.Month, date.Day), s.ProcessableSeason.End) <= 0
            )?.OriginalSeason;

        return Task.FromResult(result);
    }
}

public interface ISeason
{
    string Name { get; set; }
    DateTime Start { get; set; }
    DateTime End { get; set; }
}

internal class InternalSeason : ISeason
{
    public string Name { get; set; }
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
}

此LINQ表达式完全可以转换为SQL,因此您可以将其应用于DbSet

SQL方法

DECLARE @datum DATE;
SET @datum = '2020-12-21';

SELECT
    Season.SeasonId,
    Season.DateFrom,
    Season.DateUntil,
    CASE
        WHEN YEAR(Season.DateFrom) = YEAR(Season.DateUntil)
        THEN
            CASE
                WHEN
                    (
                        -- Season.DateFrom (2000) < NOW (2000)
                        MONTH(Season.DateFrom) < MONTH(CAST(@datum AS SQL_DATE))
                        OR (
                            MONTH(Season.DateFrom) = MONTH(CAST(@datum AS SQL_DATE))
                            AND
                            DAYOFMONTH(Season.DateFrom) <= DAYOFMONTH(CAST(@datum AS SQL_DATE))
                        )
                    )
                    AND
                    (
                        -- NOW (2000) < Season.DateUntil (2000)
                        MONTH(CAST(@datum AS SQL_DATE)) < MONTH(Season.DateUntil)
                        OR (
                            MONTH(CAST(@datum AS SQL_DATE)) = MONTH(Season.DateUntil)
                            AND
                            DAYOFMONTH(CAST(@datum AS SQL_DATE)) <= DAYOFMONTH(Season.DateUntil)
                        )
                    )
                THEN TRUE
                ELSE FALSE
            END
        ELSE
            CASE
                -- ( Season.DateFrom (2000) < NOW (2000) < 31/12) OR (1/1/2000 < NOW (2000) < Season.DateUntil (2000) )
                WHEN
                    -- Season.DateFrom (2000) < NOW (2000) < 31/12/2000)
                    (
                        (
                            -- Season.DateFrom (2000) <= NOW (2000)
                            MONTH(Season.DateFrom) < MONTH(CAST(@datum AS SQL_DATE))
                            OR (
                                MONTH(Season.DateFrom) = MONTH(CAST(@datum AS SQL_DATE))
                                AND
                                DAYOFMONTH(Season.DateFrom) <= DAYOFMONTH(CAST(@datum AS SQL_DATE))
                            )
                        )
                        AND
                        (
                            -- NOW (2000) <= 31/12)
                            MONTH(CAST(@datum AS SQL_DATE)) < 12
                            OR (
                                MONTH(CAST(@datum AS SQL_DATE)) = 12
                                AND
                                DAYOFMONTH(CAST(@datum AS SQL_DATE)) <= 31
                            )
                        )
                    )
                    OR
                    -- 1/1/2000 < NOW (2000) < Season.DateUntil (2000)
                    (
                        (
                            -- 1/1/2000 < NOW (2000)
                            1 < MONTH(CAST(@datum AS SQL_DATE))
                            OR (
                                1 = MONTH(CAST(@datum AS SQL_DATE))
                                AND
                                1 <= DAYOFMONTH(CAST(@datum AS SQL_DATE))
                            )
                        )
                        AND
                        (
                            -- NOW (2000) < Season.DateUntil (2000)
                            MONTH(CAST(@datum AS SQL_DATE)) < MONTH(Season.DateUntil)
                            OR (
                                MONTH(CAST(@datum AS SQL_DATE)) = MONTH(Season.DateUntil)
                                AND
                                DAYOFMONTH(CAST(@datum AS SQL_DATE)) <= DAYOFMONTH(Season.DateUntil)
                            )
                        )
                    )
                THEN TRUE
                ELSE FALSE
                END
        END
        AS CurrentSeason
FROM Season