Delphi周的数字功能基于系统的开始



dateutils.weekoftheyear函数很棒,但它使用了一周的ISO 8601标准定义。也就是说,一个星期被认为是从星期一开始的,并在星期日结束。我需要一个类似的功能,该功能根据本周开始的系统设置来确定周数。或至少在周日或周一的一周开始,例如MySQL的周功能。任何人都有这样的功能吗?

iso-8601 不仅包括一周的第一天这些计算的规格。例如,还有一些规则决定了今年的第一周。

尚不清楚您要寻找的是复制 iso-8601 计算这些规则的功能 Week() mySQL 的函数,或其他仅类似的东西(并且未完全定义)。

值得注意的是, mySQL week()函数接受一个参数,该参数无法确定一周开始的任意日,而是指示是否指示任何一个周日或星期一将与更改确定计算结果的许多其他规则一起使用。

相比之下,窗户本身的第一天的系统设置可以是用户希望的一周中的任何一天-MON,TUE,WED,WED,THU,THU,FRI,SAT或SUN。

我在下面提供的实现是一个简单的计算(有些人可能称其为naive),它只是根据一周的数量或零件周期返回值 0..53 指定的日期和该日期的年初。

JAN 的一周在包含指定日期的一年中被视为第0周。

因此,如果 JAN 的第1个发生在A 周日上,并且"一周开始"定义为 em> nouth 然后:

Sun, 01-Jan  = Week 0
Mon, 02-Jan  = Week 1
..
Sun, 08-Jan  = Week 1
Mon, 09-Jan  = Week 2
..
etc

实现

我将实现分为两个不同的部分。

第一个( Weekssss01jan )接受日期和参数,指示一周中的一天被视为一周的第一天。

此参数采用 tsysdayofweek 值 - 安排的枚举,使每天的序数值对应于一周中的系统环境设置中使用的值。( rtl dayofweek 函数使用的值使用不同的值,在此代码中定义为 trtldayofweek )。/p>

实施的第二部分提供了 localeweeksssiss01jan ,以演示为当前用户获得定义的网站定义的网站。然后,这简单地将其传递给 Weekssss01jan

type
  TSYSDayOfWeek = (sdMon, sdTue, sdWed, sdThu, sdFri, sdSat, sdSun);
  TRTLDayOfWeek = 1..7;    // Sun -> Sat

function WeeksSince01Jan(const aDate: TDateTime;
                         const aFirstDayOfWeek: TSYSDayOfWeek): Word;
const
  LOCALE_DOW : array[TRTLDayOfWeek] of TSYSDayOfWeek = (sdSun, sdMon, sdTue, sdWed, sdThu, sdFri, sdSat);
var
  y, m, d: Word;
  dayOfYearStart: TSYSDayOfWeek;
  dtYearStart: TDateTime;
  dtStartOfFirstWeekInYear: TDateTime;
  iAdjust: Integer;
begin
  // Get the date for the first day of the year and determine which
  //  day of the week (Mon-Fri) that was
  DecodeDate(aDate, y, m, d);
  dtYearStart     := EncodeDate(y, 1, 1);
  dayOfYearStart  := LOCALE_DOW[DayOfWeek(dtYearStart)];
  // Week calculation is simply the number of 7 day periods
  //  elapsed since the start of the year to the specified date,
  //  adjusted to reflect any 'offset' to the specified first day of week.
  iAdjust := Ord(dayOfYearStart) - Ord(aFirstDayOfWeek);
  result  := (((Trunc(aDate) + iAdjust) - Trunc(dtYearStart)) div 7);
end;

function LocaleWeeksSince01Jan(const aDate: TDateTime): Word;
var
  localeValue: array[0..1] of Char;
  firstDayOfWeek: TSYSDayOfWeek;
begin
  // Get the system defined first day of the week
  GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, localeValue, SizeOf(localeValue));
  firstDayOfWeek := TSYSDayOfWeek(Ord(localeValue[0]) - Ord('0'));
  result := WeeksSince01Jan(aDate, firstDayOfWeek);
end;

您有更多复杂的规则可以根据该周的天数来确定一年中的0或1周,那么您将需要相应地修改此实施。在当前实施中没有尝试满足此类需求。

用于测试

以下代码可以用作测试输出的基础(使用定义的系统一周的第一天):

const
  YEAR = 2012;
var
  d: Integer;
  dt: TDateTime;
  wk: Word;
begin
  List.Items.Clear;
  dt := EncodeDate(YEAR, 1, 1) - 7;
  for d := 1 to 380 do
  begin
    dt := dt + 1;
    wk := LocaleWeeksSince01Jan(dt);
    List.Items.Add(Format('%s, %s = week %d', [ShortDayNames[DayOfWeek(dt)],
                                               DateToStr(dt),
                                               wk]));
  end;

其中 list 是对 tlistbox 的引用。

更改年度的值,以产生一系列涵盖指定年度/-额外7/8天的所有日期的结果,以说明结果在年底结束时的变化前几年。

注意: 2012年是一年,它证明了在那一年返回日期的可能性,涵盖了全部潜在结果, 0..53

如果您仅对周日的一周感兴趣,而是可以在将其馈送到DateUtils.WeekOfTheYear函数之前从DateTime值中提取1天。

编辑:对David Heffernan评论的回应:

想象一下您从1月1日减去1时会发生什么

这取决于1月1日是哪一天

来自embarcadero文档:http://docwiki.embarcadero.com/libraries/xe8/en/system.dateutils.weekoftheyear

Ayear返回指定的一周发生的一年。注意 这可能与Avalue年不同。这是因为 一年的第一周定义为第一周,有四个或更多 那年的天数。这意味着,如果第一个日历日 年是星期五,星期六或周日,然后是前三个,两个 或日历年的一天,周末返回上周 前一年。同样,如果一年的最后一个日历日 是星期一,星期二或星期三,然后是最后一个,两个或 日历年的三天,每周返回1(第一个 下一个日历年的一周)。

因此,如果一周从周日而不是星期一开始,那么这意味着一周的开始和末日只是落后了一天。

因此,在这种情况下,最好将过度riddend版本与其他变量参数一起存储。

我将Deltics的出色代码与Silverwarior的简单想法结合在一起,创建一个周期开始的一周函数。

type
  TSYSDayOfWeek = (sdMon, sdTue, sdWed, sdThu, sdFri, sdSat, sdSun);
function LocaleWeekOfTheYear(dte: TDateTime): word;
var
  localeValue: array[0..1] of Char;
  firstDayOfWeek: TSYSDayOfWeek;
  yearOld,yearNew: word;
  dteNew: TDateTime;
begin
  // Get the system defined first day of the week
  GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, localeValue, SizeOf(localeValue));
  firstDayOfWeek := TSYSDayOfWeek(Ord(localeValue[0]) - Ord('0'));
  yearOld:= Year(dte);
  if (firstDayOfWeek=sdSun) then
    dteNew:= dte-1
  else 
    dteNew:= dte+Ord(firstDayOfWeek);
  yearNew:= Year(dteNew);
  if (yearOld=yearNew) then
    dte:= dteNew;
  Result:= WeekOfTheYear(dte);
end;

要使一周的第一天是星期六,我用来将2添加到现在日期的价值中。

例如WeekOf(Now + 2):让第一天是星期六, WeekOf(Now + 2):第一天是星期天, WeekOf(Now + 0):第一天是星期一,

最新更新