├── .gitignore ├── DateTimeHelper.pas ├── LICENSE.md ├── README.md └── Tests ├── TDateTimeHelper.Tests.pas ├── TDateTimeHelperTests.dpr └── TDateTimeHelperTests.dproj /.gitignore: -------------------------------------------------------------------------------- 1 | __history/ 2 | Thumbs.db 3 | .DS_Store 4 | *.~* 5 | *.bak 6 | *.BAK 7 | *.cfg 8 | *.CFG 9 | *.chm 10 | *.db 11 | *.DB 12 | *.dcu 13 | *.DCU 14 | *.ddp 15 | *.dll 16 | *.DLL 17 | *.dof 18 | *.DOF 19 | *.dres 20 | *.dsk 21 | *.DSK 22 | *.dti 23 | *.exe 24 | *.EXE 25 | *.fam 26 | *.FAM 27 | *.gid 28 | *.GID 29 | *.hlp 30 | *.HLP 31 | *.identcache 32 | *.local 33 | *.log 34 | *.map 35 | *.MAP 36 | *.mb 37 | *.MB 38 | *.net 39 | *.NET 40 | *.obj 41 | *.OBJ 42 | *.opt 43 | *.OPT 44 | *.px 45 | *.PX 46 | *.res 47 | *.RES 48 | *.scc 49 | *.tsl 50 | *.tsr 51 | *.tv 52 | *.TV 53 | *.val 54 | *.VAL 55 | *.[Xx]0* 56 | *.[Yy]0* 57 | *.[Xx][Gg]* 58 | *.[Yy][Gg]* 59 | *.zip 60 | *.ZIP 61 | dunitx-results.xml 62 | -------------------------------------------------------------------------------- /DateTimeHelper.pas: -------------------------------------------------------------------------------- 1 | { *************************************************************************** 2 | 3 | DateTimeHelper 4 | https://github.com/colinj 5 | 6 | MIT License 7 | 8 | Copyright (c) 2023 Colin Johnsun 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | *************************************************************************** } 29 | 30 | unit DateTimeHelper; 31 | 32 | interface 33 | 34 | uses 35 | System.SysUtils, System.Types, System.DateUtils; 36 | 37 | type 38 | TDateTimeHelper = record helper for TDateTime 39 | private 40 | function GetDay: Word; inline; 41 | function GetDate: TDateTime; inline; 42 | function GetDayOfWeek: Word; inline; 43 | function GetDayOfYear: Word; inline; 44 | function GetHour: Word; inline; 45 | function GetMillisecond: Word; inline; 46 | function GetMinute: Word; inline; 47 | function GetMonth: Word; inline; 48 | function GetSecond: Word; inline; 49 | function GetTime: TDateTime; inline; 50 | function GetYear: Word; inline; 51 | class function GetNow: TDateTime; static; inline; 52 | class function GetToday: TDateTime; static; inline; 53 | class function GetTomorrow: TDateTime; static; inline; 54 | class function GetYesterDay: TDateTime; static; inline; 55 | function GetUnixTime: Int64; 56 | function GetTotalSecounds: Int64; 57 | // Parse a string as TDateTime, using a string format ex.('MM/dd/yyyy hh:mm:ss') 58 | class function Parse(Date: string; aFormat: string = ''; aDateSeparator: 59 | Char = #0; aTimeSeparator: Char = #0): TDateTime; static; inline; 60 | 61 | // Parse a string as TDateTime, using local string ex. ('en-US') 62 | class function ParseLocal(Date: string; local: string = ''): TDateTime; 63 | static; inline; 64 | public 65 | class function Create(const aYear, aMonth, aDay: Word): TDateTime; overload; 66 | static; inline; 67 | class function Create(const aYear, aMonth, aDay, aHour, aMinute, aSecond, 68 | aMillisecond: Word): TDateTime; overload; static; inline; 69 | class function Create(Date: string; aFormat: string = ''; aDateSeparator: 70 | Char = #0; aTimeSeparator: Char = #0): TDateTime; overload; static; inline; 71 | class function CreateLocal(Date: string; local: string = ''): TDateTime; 72 | static; inline; 73 | class function CreateUnixTime(const Value: Int64): TDateTime; static; inline; 74 | class function CreateTotalSeconds(const Value: Int64): TDateTime; static; inline; 75 | class property Now: TDateTime read GetNow; 76 | class property Today: TDateTime read GetToday; 77 | class property Yesterday: TDateTime read GetYesterDay; 78 | class property Tomorrow: TDateTime read GetTomorrow; 79 | property Date: TDateTime read GetDate; 80 | property Time: TDateTime read GetTime; 81 | property DayOfWeek: Word read GetDayOfWeek; 82 | property DayOfYear: Word read GetDayOfYear; 83 | property Year: Word read GetYear; 84 | property Month: Word read GetMonth; 85 | property Day: Word read GetDay; 86 | property Hour: Word read GetHour; 87 | property Minute: Word read GetMinute; 88 | property Second: Word read GetSecond; 89 | property Millisecond: Word read GetMillisecond; 90 | property UnixTime: Int64 read GetUnixTime; 91 | property TotalSeconds: Int64 read GetTotalSecounds; 92 | function ToString(const aFormatStr: string = ''): string; inline; 93 | function StartOfYear: TDateTime; inline; 94 | function EndOfYear: TDateTime; inline; 95 | function StartOfMonth: TDateTime; inline; 96 | function EndOfMonth: TDateTime; inline; 97 | function StartOfWeek: TDateTime; inline; 98 | function EndOfWeek: TDateTime; inline; 99 | function StartOfDay: TDateTime; inline; 100 | function EndOfDay: TDateTime; inline; 101 | function AddYears(const aNumberOfYears: Integer = 1): TDateTime; inline; 102 | function AddMonths(const aNumberOfMonths: Integer = 1): TDateTime; inline; 103 | function AddDays(const aNumberOfDays: Integer = 1): TDateTime; inline; 104 | function AddHours(const aNumberOfHours: Int64 = 1): TDateTime; inline; 105 | function AddMinutes(const aNumberOfMinutes: Int64 = 1): TDateTime; inline; 106 | function AddSeconds(const aNumberOfSeconds: Int64 = 1): TDateTime; inline; 107 | function AddMilliseconds(const aNumberOfMilliseconds: Int64 = 1): TDateTime; inline; 108 | function CompareTo(const aDateTime: TDateTime): TValueRelationship; inline; 109 | function Equals(const aDateTime: TDateTime): Boolean; inline; 110 | function IsSameDay(const aDateTime: TDateTime): Boolean; inline; 111 | function InRange(const aStartDateTime, aEndDateTime: TDateTime; const 112 | aInclusive: Boolean = True): Boolean; inline; 113 | function IsInLeapYear: Boolean; inline; 114 | function IsToday: Boolean; inline; 115 | function IsAM: Boolean; inline; 116 | function IsPM: Boolean; inline; 117 | function YearsBetween(const aDateTime: TDateTime): Integer; inline; 118 | function MonthsBetween(const aDateTime: TDateTime): Integer; inline; 119 | function WeeksBetween(const aDateTime: TDateTime): Integer; inline; 120 | function DaysBetween(const aDateTime: TDateTime): Integer; inline; 121 | function HoursBetween(const aDateTime: TDateTime): Int64; inline; 122 | function MinutesBetween(const aDateTime: TDateTime): Int64; inline; 123 | function SecondsBetween(const aDateTime: TDateTime): Int64; inline; 124 | function MilliSecondsBetween(const aDateTime: TDateTime): Int64; inline; 125 | function WithinYears(const aDateTime: TDateTime; const aYears: Integer): 126 | Boolean; inline; 127 | function WithinMonths(const aDateTime: TDateTime; const aMonths: Integer): 128 | Boolean; inline; 129 | function WithinWeeks(const aDateTime: TDateTime; const aWeeks: Integer): 130 | Boolean; inline; 131 | function WithinDays(const aDateTime: TDateTime; const aDays: Integer): 132 | Boolean; inline; 133 | function WithinHours(const aDateTime: TDateTime; const aHours: Int64): 134 | Boolean; inline; 135 | function WithinMinutes(const aDateTime: TDateTime; const aMinutes: Int64): 136 | Boolean; inline; 137 | function WithinSeconds(const aDateTime: TDateTime; const aSeconds: Int64): 138 | Boolean; inline; 139 | function WithinMilliseconds(const aDateTime: TDateTime; const AMilliseconds: 140 | Int64): Boolean; inline; 141 | end; 142 | 143 | implementation 144 | 145 | { TDateTimeHelper } 146 | 147 | function TDateTimeHelper.AddDays(const aNumberOfDays: Integer): TDateTime; 148 | begin 149 | Result := IncDay(Self, aNumberOfDays); 150 | end; 151 | 152 | function TDateTimeHelper.AddHours(const aNumberOfHours: Int64): TDateTime; 153 | begin 154 | Result := IncHour(Self, aNumberOfHours); 155 | end; 156 | 157 | function TDateTimeHelper.AddMilliseconds(const aNumberOfMilliseconds: Int64): TDateTime; 158 | begin 159 | Result := IncMilliSecond(Self, aNumberOfMilliseconds); 160 | end; 161 | 162 | function TDateTimeHelper.AddMinutes(const aNumberOfMinutes: Int64): TDateTime; 163 | begin 164 | Result := IncMinute(Self, aNumberOfMinutes); 165 | end; 166 | 167 | function TDateTimeHelper.AddMonths(const aNumberOfMonths: Integer): TDateTime; 168 | begin 169 | Result := IncMonth(Self, aNumberOfMonths); 170 | end; 171 | 172 | function TDateTimeHelper.AddSeconds(const aNumberOfSeconds: Int64): TDateTime; 173 | begin 174 | Result := IncSecond(Self, aNumberOfSeconds); 175 | end; 176 | 177 | function TDateTimeHelper.AddYears(const aNumberOfYears: Integer): TDateTime; 178 | begin 179 | Result := IncYear(Self, aNumberOfYears); 180 | end; 181 | 182 | function TDateTimeHelper.CompareTo(const aDateTime: TDateTime): TValueRelationship; 183 | begin 184 | Result := CompareDateTime(Self, aDateTime); 185 | end; 186 | 187 | class function TDateTimeHelper.Create(const aYear, aMonth, aDay: Word): TDateTime; 188 | begin 189 | Result := EncodeDate(aYear, aMonth, aDay); 190 | end; 191 | 192 | class function TDateTimeHelper.Create(const aYear, aMonth, aDay, aHour, aMinute, 193 | aSecond, aMillisecond: Word): TDateTime; 194 | begin 195 | Result := EncodeDateTime(aYear, aMonth, aDay, aHour, aMinute, aSecond, aMillisecond); 196 | end; 197 | 198 | class function TDateTimeHelper.CreateTotalSeconds(const Value: Int64): TDateTime; 199 | begin 200 | Result := (Value / 86400); 201 | end; 202 | 203 | class function TDateTimeHelper.CreateUnixTime(const Value: Int64): TDateTime; 204 | begin 205 | Result := (Value / 86400) + 25569; 206 | end; 207 | 208 | function TDateTimeHelper.DaysBetween(const aDateTime: TDateTime): Integer; 209 | begin 210 | Result := System.DateUtils.DaysBetween(Self, aDateTime); 211 | end; 212 | 213 | function TDateTimeHelper.EndOfDay: TDateTime; 214 | begin 215 | Result := EndOfTheDay(Self); 216 | end; 217 | 218 | function TDateTimeHelper.EndOfMonth: TDateTime; 219 | begin 220 | Result := EndOfTheMonth(Self); 221 | end; 222 | 223 | function TDateTimeHelper.EndOfWeek: TDateTime; 224 | begin 225 | Result := EndOfTheWeek(Self); 226 | end; 227 | 228 | function TDateTimeHelper.EndOfYear: TDateTime; 229 | begin 230 | Result := EndOfTheYear(Self); 231 | end; 232 | 233 | function TDateTimeHelper.Equals(const aDateTime: TDateTime): Boolean; 234 | begin 235 | Result := SameDateTime(Self, aDateTime); 236 | end; 237 | 238 | function TDateTimeHelper.GetDate: TDateTime; 239 | begin 240 | Result := DateOf(Self); 241 | end; 242 | 243 | function TDateTimeHelper.GetDay: Word; 244 | begin 245 | Result := DayOf(Self); 246 | end; 247 | 248 | function TDateTimeHelper.GetDayOfWeek: Word; 249 | begin 250 | Result := DayOfTheWeek(Self); 251 | end; 252 | 253 | function TDateTimeHelper.GetDayOfYear: Word; 254 | begin 255 | Result := DayOfTheYear(Self); 256 | end; 257 | 258 | function TDateTimeHelper.GetHour: Word; 259 | begin 260 | Result := HourOf(Self); 261 | end; 262 | 263 | function TDateTimeHelper.GetMillisecond: Word; 264 | begin 265 | Result := MilliSecondOf(Self); 266 | end; 267 | 268 | function TDateTimeHelper.GetMinute: Word; 269 | begin 270 | Result := MinuteOf(Self); 271 | end; 272 | 273 | function TDateTimeHelper.GetMonth: Word; 274 | begin 275 | Result := MonthOf(Self); 276 | end; 277 | 278 | class function TDateTimeHelper.GetNow: TDateTime; 279 | begin 280 | Result := System.SysUtils.Now; 281 | end; 282 | 283 | function TDateTimeHelper.GetSecond: Word; 284 | begin 285 | Result := SecondOf(Self); 286 | end; 287 | 288 | function TDateTimeHelper.GetTime: TDateTime; 289 | begin 290 | Result := TimeOf(Self); 291 | end; 292 | 293 | class function TDateTimeHelper.GetToday: TDateTime; 294 | begin 295 | Result := System.SysUtils.Date; 296 | end; 297 | 298 | class function TDateTimeHelper.GetTomorrow: TDateTime; 299 | begin 300 | Result := System.SysUtils.Date + 1; 301 | end; 302 | 303 | function TDateTimeHelper.GetTotalSecounds: Int64; 304 | begin 305 | Result := Trunc(86400 * self); 306 | end; 307 | 308 | function TDateTimeHelper.GetUnixTime: Int64; 309 | begin 310 | Result := Trunc((self - 25569) * 86400); 311 | end; 312 | 313 | function TDateTimeHelper.GetYear: Word; 314 | begin 315 | Result := YearOf(Self); 316 | end; 317 | 318 | class function TDateTimeHelper.GetYesterDay: TDateTime; 319 | begin 320 | Result := System.SysUtils.Date - 1; 321 | end; 322 | 323 | function TDateTimeHelper.HoursBetween(const aDateTime: TDateTime): Int64; 324 | begin 325 | Result := System.DateUtils.HoursBetween(Self, aDateTime); 326 | end; 327 | 328 | function TDateTimeHelper.InRange(const aStartDateTime, aEndDateTime: TDateTime; 329 | const aInclusive: Boolean): Boolean; 330 | begin 331 | Result := DateTimeInRange(Self, aStartDateTime, aEndDateTime, aInclusive); 332 | end; 333 | 334 | function TDateTimeHelper.IsAM: Boolean; 335 | begin 336 | Result := System.DateUtils.IsAM(Self); 337 | end; 338 | 339 | function TDateTimeHelper.IsInLeapYear: Boolean; 340 | begin 341 | Result := System.DateUtils.IsInLeapYear(Self); 342 | end; 343 | 344 | function TDateTimeHelper.IsPM: Boolean; 345 | begin 346 | Result := System.DateUtils.IsPM(Self); 347 | end; 348 | 349 | function TDateTimeHelper.IsSameDay(const aDateTime: TDateTime): Boolean; 350 | begin 351 | Result := System.DateUtils.IsSameDay(Self, aDateTime); 352 | end; 353 | 354 | function TDateTimeHelper.IsToday: Boolean; 355 | begin 356 | Result := System.DateUtils.IsToday(Self); 357 | end; 358 | 359 | function TDateTimeHelper.MilliSecondsBetween(const aDateTime: TDateTime): Int64; 360 | begin 361 | Result := System.DateUtils.MilliSecondsBetween(Self, aDateTime); 362 | end; 363 | 364 | function TDateTimeHelper.MinutesBetween(const aDateTime: TDateTime): Int64; 365 | begin 366 | Result := System.DateUtils.MinutesBetween(Self, aDateTime); 367 | end; 368 | 369 | function TDateTimeHelper.MonthsBetween(const aDateTime: TDateTime): Integer; 370 | begin 371 | Result := System.DateUtils.MonthsBetween(Self, aDateTime); 372 | end; 373 | 374 | function TDateTimeHelper.SecondsBetween(const aDateTime: TDateTime): Int64; 375 | begin 376 | Result := System.DateUtils.SecondsBetween(Self, aDateTime); 377 | end; 378 | 379 | function TDateTimeHelper.StartOfDay: TDateTime; 380 | begin 381 | Result := StartOfTheDay(Self); 382 | end; 383 | 384 | function TDateTimeHelper.StartOfMonth: TDateTime; 385 | begin 386 | Result := StartOfTheMonth(Self); 387 | end; 388 | 389 | function TDateTimeHelper.StartOfWeek: TDateTime; 390 | begin 391 | Result := StartOfTheWeek(Self); 392 | end; 393 | 394 | function TDateTimeHelper.StartOfYear: TDateTime; 395 | begin 396 | Result := StartOfTheYear(Self); 397 | end; 398 | 399 | function TDateTimeHelper.ToString(const aFormatStr: string): string; 400 | begin 401 | if aFormatStr = '' then 402 | Result := DateToStr(Self) 403 | else 404 | Result := FormatDateTime(aFormatStr, Self); 405 | end; 406 | 407 | function TDateTimeHelper.WeeksBetween(const aDateTime: TDateTime): Integer; 408 | begin 409 | Result := System.DateUtils.WeeksBetween(Self, aDateTime); 410 | end; 411 | 412 | function TDateTimeHelper.WithinDays(const aDateTime: TDateTime; const aDays: 413 | Integer): Boolean; 414 | begin 415 | Result := System.DateUtils.WithinPastDays(Self, aDateTime, aDays); 416 | end; 417 | 418 | function TDateTimeHelper.WithinHours(const aDateTime: TDateTime; const aHours: 419 | Int64): Boolean; 420 | begin 421 | Result := System.DateUtils.WithinPastHours(Self, aDateTime, aHours); 422 | end; 423 | 424 | function TDateTimeHelper.WithinMilliseconds(const aDateTime: TDateTime; const 425 | AMilliseconds: Int64): Boolean; 426 | begin 427 | Result := System.DateUtils.WithinPastMilliSeconds(Self, aDateTime, AMilliseconds); 428 | end; 429 | 430 | function TDateTimeHelper.WithinMinutes(const aDateTime: TDateTime; const 431 | aMinutes: Int64): Boolean; 432 | begin 433 | Result := System.DateUtils.WithinPastMinutes(Self, aDateTime, aMinutes); 434 | end; 435 | 436 | function TDateTimeHelper.WithinMonths(const aDateTime: TDateTime; const aMonths: 437 | Integer): Boolean; 438 | begin 439 | Result := System.DateUtils.WithinPastMonths(Self, aDateTime, aMonths); 440 | end; 441 | 442 | function TDateTimeHelper.WithinSeconds(const aDateTime: TDateTime; const 443 | aSeconds: Int64): Boolean; 444 | begin 445 | Result := System.DateUtils.WithinPastSeconds(Self, aDateTime, aSeconds); 446 | end; 447 | 448 | function TDateTimeHelper.WithinWeeks(const aDateTime: TDateTime; const aWeeks: 449 | Integer): Boolean; 450 | begin 451 | Result := System.DateUtils.WithinPastWeeks(Self, aDateTime, aWeeks); 452 | end; 453 | 454 | function TDateTimeHelper.WithinYears(const aDateTime: TDateTime; const aYears: 455 | Integer): Boolean; 456 | begin 457 | Result := System.DateUtils.WithinPastYears(Self, aDateTime, aYears); 458 | end; 459 | 460 | function TDateTimeHelper.YearsBetween(const aDateTime: TDateTime): Integer; 461 | begin 462 | Result := System.DateUtils.YearsBetween(Self, aDateTime); 463 | end; 464 | 465 | class function TDateTimeHelper.Parse(Date: string; aFormat: string = ''; 466 | aDateSeparator: Char = #0; aTimeSeparator: Char = #0): TDateTime; 467 | var 468 | fs: TFormatSettings; 469 | aFormats: TArray; 470 | aLength: Integer; 471 | begin 472 | aFormats := aFormat.split([' ']); 473 | 474 | aLength := Length(aFormats); 475 | 476 | if aLength = 0 then 477 | exit(StrToDateTime(Date)); 478 | 479 | GetLocaleFormatSettings(SysLocale.DefaultLCID, fs); 480 | with fs do 481 | begin 482 | 483 | if aDateSeparator <> #0 then 484 | DateSeparator := aDateSeparator; 485 | 486 | if not aFormats[0].Trim.IsEmpty then 487 | ShortDateFormat := aFormats[0]; 488 | 489 | if aLength > 1 then 490 | begin 491 | if aTimeSeparator <> #0 then 492 | TimeSeparator := aTimeSeparator; 493 | 494 | if not aFormats[1].Trim.IsEmpty then 495 | ShortTimeFormat := aFormats[1]; 496 | end; 497 | end; 498 | Result := StrToDateTime(Date, fs); 499 | end; 500 | 501 | class function TDateTimeHelper.ParseLocal(Date: string; local: string = ''): TDateTime; 502 | var 503 | fs: TFormatSettings; 504 | begin 505 | if local.Trim.IsEmpty then 506 | fs := TFormatSettings.Create(SysLocale.DefaultLCID) 507 | else 508 | fs := TFormatSettings.Create(local); 509 | 510 | Result := StrToDateTime(Date, fs); 511 | end; 512 | 513 | class function TDateTimeHelper.Create(Date, aFormat: string; aDateSeparator, 514 | aTimeSeparator: Char): TDateTime; 515 | begin 516 | Result := Parse(Date, aFormat, aDateSeparator, aTimeSeparator); 517 | end; 518 | 519 | class function TDateTimeHelper.CreateLocal(Date, local: string): TDateTime; 520 | begin 521 | Result:= ParseLocal(Date,local); 522 | end; 523 | 524 | end. 525 | 526 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Colin Johnsun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TDateTimeHelper 2 | 3 | A TDateTime helper record for Delphi XE3 and above. 4 | 5 | One of the new language features for XE3 and above are record helpers for simple types. 6 | 7 | To learn a little bit more, I decided to make a record helper for the TDateTime type. It's a very simple record helper which pretty much calls the existing date time functions that are in the DateUtils unit. One benefit is that it allows you to assign and manipulate datetime values very easily. 8 | 9 | Getting Started 10 | --------------- 11 | 1. Download the DateTimeHelper unit. 12 | 2. Add DateTimeHelper unit to your project. 13 | 3. Add DateTimeHelper to the `uses` clause in the `implementation` section of your unit. 14 | 15 | And that's it! You now should be able to see the additional methods on TDateTime types via CodeInsight in your Delphi IDE. 16 | 17 | **_Note:_** The limitation of helper records is that only one helper is active/available per class type. If you have more than one helper for a class type then it is the last one defined in the uses clause that will be active. 18 | 19 | 20 | **Example** 21 | ```delphi 22 | uses DateTimeHelper; 23 | 24 | var 25 | T1, T2: TDateTime; 26 | 27 | begin 28 | // Set date to 14th September 2012 29 | T1 := TDateTime.Create(2012, 9, 14); 30 | 31 | // Set date to today's date 32 | T1 := TDateTime.Today; 33 | 34 | // Set T2 to 1 year, 3 months and 10 days ahead of T1. 35 | T2 := T1.AddYears(1).AddMonths(3).AddDays(10); 36 | 37 | if T2.IsInLeapYear then 38 | WriteLn(Format('%d is a leap year', [T2.Year])); 39 | 40 | T1 := TDateTime.Create(1995, 2, 14); // Delphi's birthday 41 | 42 | WriteLn(Format('Delphi is %d years old today.', [T1.YearsBetween(Now)])); 43 | WriteLn('Delphi''s birthday was ' + T1.ToString('dd/mm/yyyy')); 44 | end; 45 | ``` 46 | An important rule that I have applied in creating this record helper is that TDateTime is a value type and therefore is **immutable**. This means all helper methods will create and **return a new value** and **not change the current value** of the calling TDateTime variable (unless explicitly assigned). 47 | 48 | **Example** 49 | ```delphi 50 | T1 := TDateTime.Create(2016, 09, 14); 51 | 52 | WriteLn(T1.AddYears(2).ToString); // will return 14/09/2018 53 | WriteLn(T1.ToString); // T1 is unchanged and will still be 14/09/2016. 54 | ``` 55 | 56 | To Do 57 | ----- 58 | Need to add unit tests! 59 | 60 | 61 | Contribute 62 | ---------- 63 | I'm open to any new ideas to make this helper record be more consistent in every day use. Please clone the repo and send your pull requests if you would like to add some unit tests, new methods, and any other ideas that would make TDateTimeHelper indispensible. 64 | -------------------------------------------------------------------------------- /Tests/TDateTimeHelper.Tests.pas: -------------------------------------------------------------------------------- 1 | unit TDateTimeHelper.Tests; 2 | 3 | interface 4 | 5 | uses 6 | DUnitX.TestFramework; 7 | 8 | type 9 | [TestFixture] 10 | TDateTimeHelperTestObject = class(TObject) 11 | private 12 | FActual: TDateTime; 13 | FExpected: TDateTime; 14 | public 15 | [Setup] 16 | procedure Setup; 17 | [Test] 18 | procedure DateTime_Create; 19 | [Test] 20 | procedure DateTime_Date; 21 | [Test] 22 | procedure DateTime_DayOfWeek; 23 | [Test] 24 | procedure DateTime_DayOfYear; 25 | [Test] 26 | procedure DateTime_Year; 27 | [Test] 28 | procedure DateTime_Hour; 29 | [Test] 30 | procedure DateTime_Minute; 31 | [Test] 32 | procedure DateTime_Second; 33 | [Test] 34 | procedure DateTime_Millisecond; 35 | [Test] 36 | procedure DateTime_StartOfYear; 37 | [Test] 38 | procedure DateTime_EndOfYear; 39 | [Test] 40 | procedure DateTime_StartOfMonth; 41 | [Test] 42 | procedure DateTime_EndOfMonth; 43 | [Test] 44 | procedure DateTime_StartOfWeek; 45 | [Test] 46 | procedure DateTime_EndOfWeek; 47 | [Test] 48 | procedure DateTime_StartOfDay; 49 | [Test] 50 | procedure DateTime_EndOfDay; 51 | [Test] 52 | procedure DateTime_Create_Unixtime; 53 | [Test] 54 | procedure DateTime_Create_TotalSecounds; 55 | [Test] 56 | procedure DateTime_Create_AsString; 57 | [Test] 58 | procedure DateTime_Create_AsLocalString; 59 | [Test] 60 | procedure DateTime_Create_AsLocalString2; 61 | [Test] 62 | procedure DateTime_TotalSecounds; 63 | [Test] 64 | procedure DateTime_UnixTime; 65 | end; 66 | 67 | implementation 68 | 69 | uses 70 | System.SysUtils, System.DateUtils, DateTimeHelper; 71 | 72 | const 73 | YEAR_VAL = 1995; 74 | MONTH_VAL = 2; 75 | DAY_VAL = 14; 76 | HOUR_VAL = 10; 77 | MIN_VAL = 25; 78 | SEC_VAL = 15; 79 | MSEC_VAL = 120; 80 | 81 | { TDateTimeHelperTestObject } 82 | 83 | procedure TDateTimeHelperTestObject.Setup; 84 | begin 85 | FActual := TDateTime.Create(YEAR_VAL, MONTH_VAL, DAY_VAL, HOUR_VAL, MIN_VAL, 86 | SEC_VAL, MSEC_VAL); 87 | FExpected := EncodeDateTime(YEAR_VAL, MONTH_VAL, DAY_VAL, HOUR_VAL, MIN_VAL, 88 | SEC_VAL, MSEC_VAL); 89 | end; 90 | 91 | procedure TDateTimeHelperTestObject.DateTime_Create; 92 | begin 93 | Assert.AreEqual(FExpected, FActual); 94 | end; 95 | 96 | procedure TDateTimeHelperTestObject.DateTime_Date; 97 | begin 98 | Assert.AreEqual(DateOf(FExpected), FActual.Date); 99 | end; 100 | 101 | procedure TDateTimeHelperTestObject.DateTime_DayOfWeek; 102 | begin 103 | Assert.AreEqual(DayOfTheWeek(FExpected), FActual.DayOfWeek); 104 | end; 105 | 106 | procedure TDateTimeHelperTestObject.DateTime_DayOfYear; 107 | begin 108 | Assert.AreEqual(DayOfTheYear(FExpected), FActual.DayOfYear); 109 | end; 110 | 111 | procedure TDateTimeHelperTestObject.DateTime_Year; 112 | begin 113 | Assert.AreEqual(YearOf(FExpected), FActual.Year); 114 | end; 115 | 116 | procedure TDateTimeHelperTestObject.DateTime_Hour; 117 | begin 118 | Assert.AreEqual(HourOf(FExpected), FActual.Hour); 119 | end; 120 | 121 | procedure TDateTimeHelperTestObject.DateTime_Minute; 122 | begin 123 | Assert.AreEqual(MinuteOf(FExpected), FActual.Minute); 124 | end; 125 | 126 | procedure TDateTimeHelperTestObject.DateTime_Second; 127 | begin 128 | Assert.AreEqual(SecondOf(FExpected), FActual.Second); 129 | end; 130 | 131 | procedure TDateTimeHelperTestObject.DateTime_Millisecond; 132 | begin 133 | Assert.AreEqual(MilliSecondOf(FExpected), FActual.Millisecond); 134 | end; 135 | 136 | procedure TDateTimeHelperTestObject.DateTime_StartOfYear; 137 | begin 138 | Assert.AreEqual(StartOfTheYear(FExpected), FActual.StartOfYear); 139 | end; 140 | 141 | procedure TDateTimeHelperTestObject.DateTime_EndOfYear; 142 | begin 143 | Assert.AreEqual(EndOfTheYear(FExpected), FActual.EndOfYear); 144 | end; 145 | 146 | procedure TDateTimeHelperTestObject.DateTime_StartOfMonth; 147 | begin 148 | Assert.AreEqual(StartOfTheMonth(FExpected), FActual.StartOfMonth); 149 | end; 150 | 151 | procedure TDateTimeHelperTestObject.DateTime_EndOfMonth; 152 | begin 153 | Assert.AreEqual(EndOfTheMonth(FExpected), FActual.EndOfMonth); 154 | end; 155 | 156 | procedure TDateTimeHelperTestObject.DateTime_StartOfWeek; 157 | begin 158 | Assert.AreEqual(StartOfTheWeek(FExpected), FActual.StartOfWeek); 159 | end; 160 | 161 | procedure TDateTimeHelperTestObject.DateTime_EndOfWeek; 162 | begin 163 | Assert.AreEqual(EndOfTheWeek(FExpected), FActual.EndOfWeek); 164 | end; 165 | 166 | procedure TDateTimeHelperTestObject.DateTime_StartOfDay; 167 | begin 168 | Assert.AreEqual(StartOfTheDay(FExpected), FActual.StartOfDay); 169 | end; 170 | 171 | procedure TDateTimeHelperTestObject.DateTime_EndOfDay; 172 | begin 173 | Assert.AreEqual(EndOfTheDay(FExpected), FActual.EndOfDay); 174 | end; 175 | 176 | procedure TDateTimeHelperTestObject.DateTime_Create_Unixtime; 177 | var 178 | FExpected, FActual:TDateTime; 179 | Utime:Int64; 180 | begin 181 | FExpected := EncodeDateTime(YEAR_VAL, MONTH_VAL, DAY_VAL, HOUR_VAL, MIN_VAL, 182 | SEC_VAL, 0); 183 | Utime:= DateTimeToUnix(FExpected); 184 | FActual := TDateTime.CreateUnixTime(Utime); 185 | Assert.AreEqual(FExpected, FActual); 186 | end; 187 | 188 | procedure TDateTimeHelperTestObject.DateTime_Create_AsString; 189 | var 190 | FExpected, FActual:TDateTime; 191 | begin 192 | FExpected := EncodeDateTime(YEAR_VAL, MONTH_VAL, DAY_VAL, HOUR_VAL, MIN_VAL, 193 | SEC_VAL, 0); 194 | 195 | FActual := TDateTime.Create('02/14/1995 10:25:15','MM/dd/yyyy hh:mm:ss'); 196 | Assert.AreEqual(FExpected, FActual); 197 | end; 198 | 199 | procedure TDateTimeHelperTestObject.DateTime_Create_TotalSecounds; 200 | var 201 | FExpected, FActual:TDateTime; 202 | TotalSecounds:Int64; 203 | begin 204 | FExpected := EncodeDateTime(YEAR_VAL, MONTH_VAL, DAY_VAL, HOUR_VAL, MIN_VAL, 205 | SEC_VAL, 0); 206 | TotalSecounds := SecondsBetween(FExpected, 0); 207 | 208 | FActual := TDateTime.CreateTotalSeconds(TotalSecounds); 209 | Assert.AreEqual(FExpected, FActual); 210 | end; 211 | 212 | procedure TDateTimeHelperTestObject.DateTime_Create_AsLocalString; 213 | var 214 | FExpected, FActual:TDateTime; 215 | begin 216 | FExpected := EncodeDateTime(YEAR_VAL, MONTH_VAL, DAY_VAL, HOUR_VAL, MIN_VAL, 217 | SEC_VAL, 0); 218 | 219 | FActual := TDateTime.CreateLocal('02/14/1995 10:25:15','en-US'); 220 | Assert.AreEqual(FExpected, FActual); 221 | end; 222 | 223 | procedure TDateTimeHelperTestObject.DateTime_Create_AsLocalString2; 224 | var 225 | FExpected, FActual:TDateTime; 226 | begin 227 | FExpected := EncodeDateTime(YEAR_VAL, MONTH_VAL, DAY_VAL, HOUR_VAL, MIN_VAL, 228 | SEC_VAL, 0); 229 | 230 | FActual := TDateTime.CreateLocal('14/02/1995 10:25:15','en-GB'); 231 | Assert.AreEqual(FExpected, FActual); 232 | end; 233 | 234 | procedure TDateTimeHelperTestObject.DateTime_TotalSecounds; 235 | var 236 | Expected, Actual:Int64; 237 | begin 238 | Expected:= SecondsBetween(FExpected, 0); 239 | Actual := FActual.TotalSeconds; 240 | Assert.AreEqual(Expected, Actual); 241 | end; 242 | 243 | procedure TDateTimeHelperTestObject.DateTime_UnixTime; 244 | var 245 | Expected, Actual:Int64; 246 | begin 247 | Expected:= DateTimeToUnix(FExpected); 248 | Actual := FActual.UnixTime; 249 | Assert.AreEqual(Expected, Actual); 250 | end; 251 | 252 | initialization 253 | TDUnitX.RegisterTestFixture(TDateTimeHelperTestObject); 254 | 255 | end. 256 | 257 | -------------------------------------------------------------------------------- /Tests/TDateTimeHelperTests.dpr: -------------------------------------------------------------------------------- 1 | program TDateTimeHelperTests; 2 | 3 | {$IFNDEF TESTINSIGHT} 4 | {$APPTYPE CONSOLE} 5 | {$ENDIF}{$STRONGLINKTYPES ON} 6 | uses 7 | System.SysUtils, 8 | DUnitX.Loggers.Console, 9 | DUnitX.Loggers.Xml.NUnit, 10 | DUnitX.TestFramework, 11 | {$IFDEF VER240} 12 | DUnitX.Init, // Workaround for Delphi XE3 Compiler Bug 13 | {$ENDIF} 14 | DateTimeHelper in '..\DateTimeHelper.pas', 15 | TDateTimeHelper.Tests in 'TDateTimeHelper.Tests.pas'; 16 | 17 | var 18 | Runner: ITestRunner; 19 | Results: IRunResults; 20 | Logger: ITestLogger; 21 | NUnitLogger: ITestLogger; 22 | begin 23 | {$IFDEF TESTINSIGHT} 24 | TestInsight.DUnitX.RunRegisteredTests; 25 | Exit; 26 | {$ENDIF} 27 | try 28 | //Check command line options, will exit if invalid 29 | TDUnitX.CheckCommandLine; 30 | //Create the test runner 31 | Runner := TDUnitX.CreateRunner; 32 | //Tell the runner to use RTTI to find Fixtures 33 | Runner.UseRTTI := True; 34 | //tell the runner how we will log things 35 | //Log to the console window 36 | Logger := TDUnitXConsoleLogger.Create(True); 37 | Runner.AddLogger(Logger); 38 | //Generate an NUnit compatible XML File 39 | NUnitLogger := TDUnitXXMLNUnitFileLogger.Create(TDUnitX.Options.XMLOutputFile); 40 | Runner.AddLogger(NUnitLogger); 41 | Runner.FailsOnNoAsserts := False; //When true, Assertions must be made during tests; 42 | 43 | //Run tests 44 | Results := Runner.Execute; 45 | if not Results.AllPassed then 46 | System.ExitCode := EXIT_ERRORS; 47 | 48 | {$IFNDEF CI} 49 | //We don't want this happening when running under CI. 50 | if TDUnitX.Options.ExitBehavior = TDUnitXExitBehavior.Pause then 51 | begin 52 | System.Write('Done.. press key to quit.'); 53 | System.Readln; 54 | end; 55 | {$ENDIF} 56 | except 57 | on E: Exception do 58 | System.Writeln(E.ClassName, ': ', E.Message); 59 | end; 60 | end. 61 | -------------------------------------------------------------------------------- /Tests/TDateTimeHelperTests.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {E992A111-A05C-4625-AB5A-2B563821B4BE} 4 | 18.8 5 | None 6 | TDateTimeHelperTests.dpr 7 | True 8 | Debug 9 | Win32 10 | 1 11 | Console 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Base 34 | true 35 | 36 | 37 | true 38 | Base 39 | true 40 | 41 | 42 | true 43 | Base 44 | true 45 | 46 | 47 | true 48 | Base 49 | true 50 | 51 | 52 | true 53 | Base 54 | true 55 | 56 | 57 | true 58 | Base 59 | true 60 | 61 | 62 | true 63 | Cfg_1 64 | true 65 | true 66 | 67 | 68 | true 69 | Base 70 | true 71 | 72 | 73 | true 74 | Cfg_2 75 | true 76 | true 77 | 78 | 79 | true 80 | Cfg_2 81 | true 82 | true 83 | 84 | 85 | $(DUnitX);$(DCC_UnitSearchPath) 86 | bindcompfmx;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;xmlrtl;ibxpress;DbxCommonDriver;IndyProtocols;DBXMySQLDriver;dbxcds;soaprtl;bindengine;FMXTee;dsnap;IndyCore;fmxase;CloudService;FmxTeeUI;inet;fmxobj;inetdbxpress;fmxdae;dbexpress;$(DCC_UsePackage) 87 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 88 | $(BDS)\bin\delphi_PROJECTICON.ico 89 | .\$(Platform)\$(Config) 90 | .\$(Platform)\$(Config) 91 | false 92 | false 93 | false 94 | false 95 | false 96 | TDateTimeHelperTests 97 | $(BDS)\bin\delphi_PROJECTICNS.icns 98 | 99 | 100 | package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= 101 | Debug 102 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png 103 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png 104 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png 105 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png 106 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png 107 | $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png 108 | $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png 109 | $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png 110 | $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png 111 | true 112 | true 113 | true 114 | true 115 | true 116 | true 117 | true 118 | true 119 | true 120 | true 121 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png 122 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png 123 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png 124 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png 125 | $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png 126 | android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar 127 | 128 | 129 | CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSLocationAlwaysAndWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSPhotoLibraryAddUsageDescription=The reason for adding to the photo library;NSCameraUsageDescription=The reason for accessing the camera;NSFaceIDUsageDescription=The reason for accessing the face id;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSSiriUsageDescription=The reason for accessing Siri;ITSAppUsesNonExemptEncryption=false 130 | iPhoneAndiPad 131 | true 132 | Debug 133 | $(MSBuildProjectName) 134 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png 135 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png 136 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png 137 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png 138 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png 139 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png 140 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png 141 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png 142 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png 143 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png 144 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png 145 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png 146 | 147 | 148 | CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSLocationAlwaysAndWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSPhotoLibraryAddUsageDescription=The reason for adding to the photo library;NSCameraUsageDescription=The reason for accessing the camera;NSFaceIDUsageDescription=The reason for accessing the face id;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSSiriUsageDescription=The reason for accessing Siri;ITSAppUsesNonExemptEncryption=false 149 | iPhoneAndiPad 150 | true 151 | Debug 152 | $(MSBuildProjectName) 153 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png 154 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png 155 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png 156 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png 157 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png 158 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png 159 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png 160 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png 161 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png 162 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png 163 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png 164 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png 165 | 166 | 167 | CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSLocationAlwaysAndWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSPhotoLibraryAddUsageDescription=The reason for adding to the photo library;NSCameraUsageDescription=The reason for accessing the camera;NSFaceIDUsageDescription=The reason for accessing the face id;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSSiriUsageDescription=The reason for accessing Siri;ITSAppUsesNonExemptEncryption=false 168 | iPhoneAndiPad 169 | true 170 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png 171 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png 172 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png 173 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png 174 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png 175 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png 176 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png 177 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png 178 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png 179 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png 180 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png 181 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png 182 | 183 | 184 | $(BDS)\bin\delphi_PROJECTICNS.icns 185 | 186 | 187 | CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts 188 | Debug 189 | true 190 | Base 191 | true 192 | 193 | 194 | vcldbx;frx16;TeeDB;vclib;inetdbbde;Tee;svnui;vclimg;frxDB16;intrawebdb_120_160;fmi;fs16;vclactnband;TeeUI;vcldb;bindcompvcl;vcldsnap;vclie;vcltouch;Intraweb_120_160;websnap;vclribbon;frxe16;VclSmp;fsDB16;vcl;CodeSiteExpressPkg;dsnapcon;vclx;webdsnap;svn;bdertl;adortl;$(DCC_UsePackage) 195 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 196 | 1033 197 | CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) 198 | 199 | 200 | TeeDB;vclib;Tee;vclimg;vclactnband;TeeUI;vcldb;bindcompvcl;vcldsnap;vclie;vcltouch;websnap;vclribbon;VclSmp;vcl;dsnapcon;vclx;webdsnap;adortl;$(DCC_UsePackage) 201 | 202 | 203 | DEBUG;$(DCC_Define) 204 | false 205 | true 206 | true 207 | true 208 | 209 | 210 | false 211 | 212 | 213 | false 214 | RELEASE;$(DCC_Define) 215 | 0 216 | 0 217 | 218 | 219 | $(BDS)\bin\delphi_PROJECTICNS.icns 220 | 221 | 222 | true 223 | Cfg_2 224 | true 225 | 226 | 227 | 228 | MainSource 229 | 230 | 231 | 232 | 233 | Cfg_2 234 | Base 235 | 236 | 237 | Base 238 | 239 | 240 | Cfg_1 241 | Base 242 | 243 | 244 | 245 | Delphi.Personality.12 246 | 247 | 248 | 249 | 250 | False 251 | False 252 | 1 253 | 0 254 | 0 255 | 0 256 | False 257 | False 258 | False 259 | False 260 | False 261 | 3081 262 | 1252 263 | 264 | 265 | 266 | 267 | 1.0.0.0 268 | 269 | 270 | 271 | 272 | 273 | 1.0.0.0 274 | 275 | 276 | 277 | TDateTimeHelperTests.dpr 278 | 279 | 280 | 281 | 282 | 283 | true 284 | 285 | 286 | 287 | 288 | true 289 | 290 | 291 | 292 | 293 | true 294 | 295 | 296 | 297 | 298 | 1 299 | 300 | 301 | 0 302 | 303 | 304 | 305 | 306 | classes 307 | 1 308 | 309 | 310 | classes 311 | 1 312 | 313 | 314 | 315 | 316 | res\xml 317 | 1 318 | 319 | 320 | res\xml 321 | 1 322 | 323 | 324 | 325 | 326 | library\lib\armeabi-v7a 327 | 1 328 | 329 | 330 | 331 | 332 | library\lib\armeabi 333 | 1 334 | 335 | 336 | library\lib\armeabi 337 | 1 338 | 339 | 340 | 341 | 342 | library\lib\armeabi-v7a 343 | 1 344 | 345 | 346 | 347 | 348 | library\lib\mips 349 | 1 350 | 351 | 352 | library\lib\mips 353 | 1 354 | 355 | 356 | 357 | 358 | library\lib\armeabi-v7a 359 | 1 360 | 361 | 362 | library\lib\arm64-v8a 363 | 1 364 | 365 | 366 | 367 | 368 | library\lib\armeabi-v7a 369 | 1 370 | 371 | 372 | 373 | 374 | res\drawable 375 | 1 376 | 377 | 378 | res\drawable 379 | 1 380 | 381 | 382 | 383 | 384 | res\values 385 | 1 386 | 387 | 388 | res\values 389 | 1 390 | 391 | 392 | 393 | 394 | res\values-v21 395 | 1 396 | 397 | 398 | res\values-v21 399 | 1 400 | 401 | 402 | 403 | 404 | res\values 405 | 1 406 | 407 | 408 | res\values 409 | 1 410 | 411 | 412 | 413 | 414 | res\drawable 415 | 1 416 | 417 | 418 | res\drawable 419 | 1 420 | 421 | 422 | 423 | 424 | res\drawable-xxhdpi 425 | 1 426 | 427 | 428 | res\drawable-xxhdpi 429 | 1 430 | 431 | 432 | 433 | 434 | res\drawable-ldpi 435 | 1 436 | 437 | 438 | res\drawable-ldpi 439 | 1 440 | 441 | 442 | 443 | 444 | res\drawable-mdpi 445 | 1 446 | 447 | 448 | res\drawable-mdpi 449 | 1 450 | 451 | 452 | 453 | 454 | res\drawable-hdpi 455 | 1 456 | 457 | 458 | res\drawable-hdpi 459 | 1 460 | 461 | 462 | 463 | 464 | res\drawable-xhdpi 465 | 1 466 | 467 | 468 | res\drawable-xhdpi 469 | 1 470 | 471 | 472 | 473 | 474 | res\drawable-mdpi 475 | 1 476 | 477 | 478 | res\drawable-mdpi 479 | 1 480 | 481 | 482 | 483 | 484 | res\drawable-hdpi 485 | 1 486 | 487 | 488 | res\drawable-hdpi 489 | 1 490 | 491 | 492 | 493 | 494 | res\drawable-xhdpi 495 | 1 496 | 497 | 498 | res\drawable-xhdpi 499 | 1 500 | 501 | 502 | 503 | 504 | res\drawable-xxhdpi 505 | 1 506 | 507 | 508 | res\drawable-xxhdpi 509 | 1 510 | 511 | 512 | 513 | 514 | res\drawable-xxxhdpi 515 | 1 516 | 517 | 518 | res\drawable-xxxhdpi 519 | 1 520 | 521 | 522 | 523 | 524 | res\drawable-small 525 | 1 526 | 527 | 528 | res\drawable-small 529 | 1 530 | 531 | 532 | 533 | 534 | res\drawable-normal 535 | 1 536 | 537 | 538 | res\drawable-normal 539 | 1 540 | 541 | 542 | 543 | 544 | res\drawable-large 545 | 1 546 | 547 | 548 | res\drawable-large 549 | 1 550 | 551 | 552 | 553 | 554 | res\drawable-xlarge 555 | 1 556 | 557 | 558 | res\drawable-xlarge 559 | 1 560 | 561 | 562 | 563 | 564 | res\values 565 | 1 566 | 567 | 568 | res\values 569 | 1 570 | 571 | 572 | 573 | 574 | 1 575 | 576 | 577 | 1 578 | 579 | 580 | 0 581 | 582 | 583 | 584 | 585 | 1 586 | .framework 587 | 588 | 589 | 1 590 | .framework 591 | 592 | 593 | 0 594 | 595 | 596 | 597 | 598 | 1 599 | .dylib 600 | 601 | 602 | 1 603 | .dylib 604 | 605 | 606 | 0 607 | .dll;.bpl 608 | 609 | 610 | 611 | 612 | 1 613 | .dylib 614 | 615 | 616 | 1 617 | .dylib 618 | 619 | 620 | 1 621 | .dylib 622 | 623 | 624 | 1 625 | .dylib 626 | 627 | 628 | 1 629 | .dylib 630 | 631 | 632 | 0 633 | .bpl 634 | 635 | 636 | 637 | 638 | 0 639 | 640 | 641 | 0 642 | 643 | 644 | 0 645 | 646 | 647 | 0 648 | 649 | 650 | 0 651 | 652 | 653 | 0 654 | 655 | 656 | 0 657 | 658 | 659 | 0 660 | 661 | 662 | 663 | 664 | 1 665 | 666 | 667 | 1 668 | 669 | 670 | 1 671 | 672 | 673 | 674 | 675 | 1 676 | 677 | 678 | 1 679 | 680 | 681 | 1 682 | 683 | 684 | 685 | 686 | 1 687 | 688 | 689 | 1 690 | 691 | 692 | 1 693 | 694 | 695 | 696 | 697 | 1 698 | 699 | 700 | 1 701 | 702 | 703 | 1 704 | 705 | 706 | 707 | 708 | 1 709 | 710 | 711 | 1 712 | 713 | 714 | 1 715 | 716 | 717 | 718 | 719 | 1 720 | 721 | 722 | 1 723 | 724 | 725 | 1 726 | 727 | 728 | 729 | 730 | 1 731 | 732 | 733 | 1 734 | 735 | 736 | 1 737 | 738 | 739 | 740 | 741 | 1 742 | 743 | 744 | 1 745 | 746 | 747 | 1 748 | 749 | 750 | 751 | 752 | 1 753 | 754 | 755 | 1 756 | 757 | 758 | 1 759 | 760 | 761 | 762 | 763 | 1 764 | 765 | 766 | 1 767 | 768 | 769 | 1 770 | 771 | 772 | 773 | 774 | 1 775 | 776 | 777 | 1 778 | 779 | 780 | 1 781 | 782 | 783 | 784 | 785 | 1 786 | 787 | 788 | 1 789 | 790 | 791 | 1 792 | 793 | 794 | 795 | 796 | 1 797 | 798 | 799 | 1 800 | 801 | 802 | 1 803 | 804 | 805 | 806 | 807 | 1 808 | 809 | 810 | 1 811 | 812 | 813 | 1 814 | 815 | 816 | 817 | 818 | 1 819 | 820 | 821 | 1 822 | 823 | 824 | 1 825 | 826 | 827 | 828 | 829 | 1 830 | 831 | 832 | 1 833 | 834 | 835 | 1 836 | 837 | 838 | 839 | 840 | 1 841 | 842 | 843 | 1 844 | 845 | 846 | 1 847 | 848 | 849 | 850 | 851 | 1 852 | 853 | 854 | 1 855 | 856 | 857 | 1 858 | 859 | 860 | 861 | 862 | 1 863 | 864 | 865 | 1 866 | 867 | 868 | 1 869 | 870 | 871 | 872 | 873 | 1 874 | 875 | 876 | 1 877 | 878 | 879 | 1 880 | 881 | 882 | 883 | 884 | 1 885 | 886 | 887 | 1 888 | 889 | 890 | 1 891 | 892 | 893 | 894 | 895 | 1 896 | 897 | 898 | 1 899 | 900 | 901 | 1 902 | 903 | 904 | 905 | 906 | 1 907 | 908 | 909 | 1 910 | 911 | 912 | 1 913 | 914 | 915 | 916 | 917 | 1 918 | 919 | 920 | 1 921 | 922 | 923 | 1 924 | 925 | 926 | 927 | 928 | 1 929 | 930 | 931 | 1 932 | 933 | 934 | 935 | 936 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 937 | 1 938 | 939 | 940 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 941 | 1 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 1 950 | 951 | 952 | 1 953 | 954 | 955 | 1 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | Contents\Resources 964 | 1 965 | 966 | 967 | Contents\Resources 968 | 1 969 | 970 | 971 | 972 | 973 | library\lib\armeabi-v7a 974 | 1 975 | 976 | 977 | library\lib\arm64-v8a 978 | 1 979 | 980 | 981 | 1 982 | 983 | 984 | 1 985 | 986 | 987 | 1 988 | 989 | 990 | 1 991 | 992 | 993 | 1 994 | 995 | 996 | 1 997 | 998 | 999 | 0 1000 | 1001 | 1002 | 1003 | 1004 | library\lib\armeabi-v7a 1005 | 1 1006 | 1007 | 1008 | 1009 | 1010 | 1 1011 | 1012 | 1013 | 1 1014 | 1015 | 1016 | 1017 | 1018 | Assets 1019 | 1 1020 | 1021 | 1022 | Assets 1023 | 1 1024 | 1025 | 1026 | 1027 | 1028 | Assets 1029 | 1 1030 | 1031 | 1032 | Assets 1033 | 1 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | False 1049 | False 1050 | False 1051 | False 1052 | False 1053 | False 1054 | False 1055 | True 1056 | False 1057 | 1058 | 1059 | 12 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | --------------------------------------------------------------------------------