validation.odin 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. package datetime
  2. // Validation helpers
  3. /*
  4. Check if a year is a leap year.
  5. */
  6. is_leap_year :: proc "contextless" (#any_int year: i64) -> (leap: bool) {
  7. return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
  8. }
  9. /*
  10. Check for errors in date formation.
  11. This procedure validates all fields of a date, and if any of the fields is
  12. outside of allowed range, an error is returned.
  13. */
  14. validate_date :: proc "contextless" (date: Date) -> (err: Error) {
  15. return validate(date.year, date.month, date.day)
  16. }
  17. /*
  18. Check for errors in date formation given date components.
  19. This procedure checks whether a date formed by the specified year month and a
  20. day is a valid date. If not, an error is returned.
  21. */
  22. validate_year_month_day :: proc "contextless" (#any_int year, #any_int month, #any_int day: i64) -> (err: Error) {
  23. if year < MIN_DATE.year || year > MAX_DATE.year {
  24. return .Invalid_Year
  25. }
  26. if month < 1 || month > 12 {
  27. return .Invalid_Month
  28. }
  29. month_days := MONTH_DAYS
  30. days_this_month := month_days[month]
  31. if month == 2 && is_leap_year(year) {
  32. days_this_month = 29
  33. }
  34. if day < 1 || day > i64(days_this_month) {
  35. return .Invalid_Day
  36. }
  37. return .None
  38. }
  39. /*
  40. Check for errors in Ordinal
  41. This procedure checks if the ordinal is in a valid range for roundtrip
  42. conversions with the dates. If not, an error is returned.
  43. */
  44. validate_ordinal :: proc "contextless" (ordinal: Ordinal) -> (err: Error) {
  45. if ordinal < MIN_ORD || ordinal > MAX_ORD {
  46. return .Invalid_Ordinal
  47. }
  48. return
  49. }
  50. /*
  51. Check for errors in time formation
  52. This procedure checks whether time has all fields in valid ranges, and if not
  53. an error is returned.
  54. */
  55. validate_time :: proc "contextless" (time: Time) -> (err: Error) {
  56. return validate(time.hour, time.minute, time.second, time.nano)
  57. }
  58. /*
  59. Check for errors in time formed by its components.
  60. This procedure checks whether the time formed by its components is valid, and
  61. if not an error is returned.
  62. */
  63. validate_hour_minute_second :: proc "contextless" (#any_int hour, #any_int minute, #any_int second, #any_int nano: i64) -> (err: Error) {
  64. if hour < 0 || hour > 23 {
  65. return .Invalid_Hour
  66. }
  67. if minute < 0 || minute > 59 {
  68. return .Invalid_Minute
  69. }
  70. if second < 0 || second > 59 {
  71. return .Invalid_Second
  72. }
  73. if nano < 0 || nano > 1e9 {
  74. return .Invalid_Nano
  75. }
  76. return .None
  77. }
  78. /*
  79. Check for errors in datetime formation.
  80. This procedure checks whether all fields of date and time in the specified
  81. datetime are valid, and if not, an error is returned.
  82. */
  83. validate_datetime :: proc "contextless" (datetime: DateTime) -> (err: Error) {
  84. validate(datetime.date) or_return
  85. validate(datetime.time) or_return
  86. return .None
  87. }
  88. /*
  89. Check for errors in date, time or datetime.
  90. */
  91. validate :: proc{
  92. validate_date,
  93. validate_year_month_day,
  94. validate_ordinal,
  95. validate_hour_minute_second,
  96. validate_time,
  97. validate_datetime,
  98. }