答案 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
,您可以使用它轻松获取季节。
在波斯日历中:
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)
我需要一种更灵活的方法。我的季节存储在数据库中,所以我不能只比较日/月。
但是,如果您尝试考虑将一个季节的开始/结束日期与特定日期进行比较的方程式,这并不像看起来那样容易,因为新年总是会咬住您的脖子。为了解决这个问题,我决定将跨新年的季节分为两个单独的季节。然后,您可以轻松地将天/月与数学逻辑进行比较,并确定正确的季节。
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
。
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