Module: FatCore::Date::ClassMethods
- Included in:
- Date
- Defined in:
- lib/fat_core/date.rb
Utilities collapse
- COMMON_YEAR_DAYS_IN_MONTH =
An Array of the number of days in each month indexed by month number, starting with January = 1, etc.
[31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31].freeze
Parsing collapse
-
#parse_american(str) ⇒ ::Date
Convert a string +str+ with an American style date into a ::Date object.
-
#parse_spec(spec, spec_type = :from) ⇒ ::Date
Convert a 'period spec'
spec
to a ::Date.
Utilities collapse
- #days_in_month(y, m) ⇒ Object
-
#easter(year) ⇒ ::Date
Return the date of Easter for the Western Church in the given year.
-
#ensure_date(dat) ⇒ Date
Ensure that date is of class Date based either on a string or Date object.
-
#nth_wday_in_year_month(n, wday, year, month) ⇒ Object
Return the nth weekday in the given month.
Instance Method Details
permalink #days_in_month(y, m) ⇒ Object
1583 1584 1585 1586 1587 1588 1589 1590 1591 |
# File 'lib/fat_core/date.rb', line 1583 def days_in_month(y, m) raise ArgumentError, 'illegal month number' if m < 1 || m > 12 days = COMMON_YEAR_DAYS_IN_MONTH[m] if m == 2 ::Date.new(y, m, 1).leap? ? 29 : 28 else days end end |
permalink #easter(year) ⇒ ::Date
Return the date of Easter for the Western Church in the given year.
1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 |
# File 'lib/fat_core/date.rb', line 1638 def easter(year) y = year a = y % 19 b, c = y.divmod(100) d, e = b.divmod(4) f = (b + 8) / 25 g = (b - f + 1) / 3 h = (19 * a + b - d - g + 15) % 30 i, k = c.divmod(4) l = (32 + 2 * e + 2 * i - h - k) % 7 m = (a + 11 * h + 22 * l) / 451 n, p = (h + l - 7 * m + 114).divmod(31) ::Date.new(y, n, p + 1) end |
permalink #ensure_date(dat) ⇒ Date
Ensure that date is of class Date based either on a string or Date object.
1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 |
# File 'lib/fat_core/date.rb', line 1658 def ensure_date(dat) case dat when String ::Date.parse(dat) when Date, DateTime dat when Time dat.to_date else raise ArgumentError, 'Date.ensure_date needs String, Date, or Time' end end |
permalink #nth_wday_in_year_month(n, wday, year, month) ⇒ Object
Return the nth weekday in the given month. If n is negative, count from last day of month.
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 |
# File 'lib/fat_core/date.rb', line 1600 def nth_wday_in_year_month(n, wday, year, month) wday = wday.to_i raise ArgumentError, 'illegal weekday number' if wday < 0 || wday > 6 month = month.to_i raise ArgumentError, 'illegal month number' if month < 1 || month > 12 n = n.to_i if n.positive? # Set d to the 1st wday in month d = ::Date.new(year, month, 1) d += 1 while d.wday != wday # Set d to the nth wday in month nd = 1 while nd != n d += 7 nd += 1 end d elsif n.negative? n = -n # Set d to the last wday in month d = ::Date.new(year, month, 1).end_of_month d -= 1 while d.wday != wday # Set d to the nth wday in month nd = 1 while nd != n d -= 7 nd += 1 end d else raise ArgumentError, 'Argument n cannot be zero' end end |
permalink #parse_american(str) ⇒ ::Date
Convert a string +str+ with an American style date into a ::Date object
An American style date is of the form MM/DD/YYYY
, that is it places the
month first, then the day of the month, and finally the year. The European
convention is typically to place the day of the month first, DD/MM/YYYY
.
A date found in the wild can be ambiguous, e.g. 3/5/2014, but a date
string known to be using the American convention can be parsed using this
method. Both the month and the day can be a single digit. The year can be
either 2 or 4 digits, and if given as 2 digits, it adds 2000 to it to give
the year.
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 |
# File 'lib/fat_core/date.rb', line 1283 def parse_american(str) unless str.to_s =~ %r{\A\s*(\d\d?)\s*/\s*(\d\d?)\s*/\s*((\d\d)?\d\d)\s*\z} raise ArgumentError, "date string must be of form 'MM?/DD?/YY(YY)?'" end year = $3.to_i month = $1.to_i day = $2.to_i year += 2000 if year < 100 ::Date.new(year, month, day) end |
permalink #parse_spec(spec, spec_type = :from) ⇒ ::Date
Convert a 'period spec' spec
to a ::Date. A date spec is a short-hand way of
specifying a calendar period either absolutely or relative to the computer
clock. This method returns the first date of that period, when spec_type
is set to :from
, the default, and returns the last date of the period
when spec_type
is :to
.
There are a number of forms the spec
can take. In each case,
::Date.parse_spec
returns the first date in the period if spec_type
is
:from
and the last date in the period if spec_type
is :to
:
YYYY
is the whole yearYYYY
,YYYY-1H
orYYYY-H1
is the first calendar half in yearYYYY
,H2
or2H
is the second calendar half of the current year,YYYY-3Q
orYYYY-Q3
is the third calendar quarter of year YYYY,Q3
or3Q
is the third calendar quarter in the current year,YYYY-04
orYYYY-4
is April, the fourth month of yearYYYY
,4-12
or04-12
is the 12th of April in the current year,4
or04
is April in the current year,YYYY-W32
orYYYY-32W
is the 32nd week in year YYYY,W32
or32W
is the 32nd week in the current year,YYYY-MM-DD
a particular date, so:from
and:to
return the same date,this_<chunk>
where<chunk>
is one ofyear
,half
,quarter
,bimonth
,month
,semimonth
,biweek
,week
, orday
, the corresponding calendar period in which the current date falls,last_<chunk>
where<chunk>
is one ofyear
,half
,quarter
,bimonth
,month
,semimonth
,biweek
,week
, orday
, the corresponding calendar period immediately before the one in which the current date falls,today
is the same asthis_day
,yesterday
is the same aslast_day
,forever
is the period from ::Date::BOT to ::Date::EOT, essentially all dates of commercial interest, andnever
causes the method to return nil.
In all of the above example specs, letter used for calendar chunks, W
,
Q
, and H
can be written in lower case as well. Also, you can use /
to separate date components instead of -
.
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 |
# File 'lib/fat_core/date.rb', line 1346 def parse_spec(spec, spec_type = :from) spec = spec.to_s.strip unless [:from, :to].include?(spec_type) raise ArgumentError, "invalid date spec type: '#{spec_type}'" end today = ::Date.current case spec.clean when /\A(\d\d\d\d)[-\/](\d\d?)[-\/](\d\d?)\z/ # A specified date ::Date.new($1.to_i, $2.to_i, $3.to_i) when /\AW(\d\d?)\z/, /\A(\d\d?)W\z/ week_num = $1.to_i if week_num < 1 || week_num > 53 raise ArgumentError, "invalid week number (1-53): '#{spec}'" end if spec_type == :from ::Date.commercial(today.year, week_num).beginning_of_week else ::Date.commercial(today.year, week_num).end_of_week end when /\A(\d\d\d\d)[-\/]W(\d\d?)\z/, /\A(\d\d\d\d)[-\/](\d\d?)W\z/ year = $1.to_i week_num = $2.to_i if week_num < 1 || week_num > 53 raise ArgumentError, "invalid week number (1-53): '#{spec}'" end if spec_type == :from ::Date.commercial(year, week_num).beginning_of_week else ::Date.commercial(year, week_num).end_of_week end when /^(\d\d\d\d)[-\/](\d)[Qq]$/, /^(\d\d\d\d)[-\/][Qq](\d)$/ # Year-Quarter year = $1.to_i quarter = $2.to_i unless [1, 2, 3, 4].include?(quarter) raise ArgumentError, "invalid quarter number (1-4): '#{spec}'" end month = quarter * 3 if spec_type == :from ::Date.new(year, month, 1).beginning_of_quarter else ::Date.new(year, month, 1).end_of_quarter end when /^([1234])[qQ]$/, /^[qQ]([1234])$/ # Quarter only this_year = today.year quarter = $1.to_i unless [1, 2, 3, 4].include?(quarter) raise ArgumentError, "invalid quarter number (1-4): '#{spec}'" end date = ::Date.new(this_year, quarter * 3, 15) if spec_type == :from date.beginning_of_quarter else date.end_of_quarter end when /^(\d\d\d\d)[-\/](\d)[Hh]$/, /^(\d\d\d\d)[-\/][Hh](\d)$/ # Year-Half year = $1.to_i half = $2.to_i unless [1, 2].include?(half) raise ArgumentError, "invalid half number: '#{spec}'" end month = half * 6 if spec_type == :from ::Date.new(year, month, 15).beginning_of_half else ::Date.new(year, month, 1).end_of_half end when /^([12])[hH]$/, /^[hH]([12])$/ # Half only this_year = today.year half = $1.to_i unless [1, 2].include?(half) raise ArgumentError, "invalid half number: '#{spec}'" end date = ::Date.new(this_year, half * 6, 15) if spec_type == :from date.beginning_of_half else date.end_of_half end when /^(\d\d\d\d)[-\/](\d\d?)*$/ # Year-Month only year = $1.to_i month = $2.to_i unless [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].include?(month) raise ArgumentError, "invalid month number (1-12): '#{spec}'" end if spec_type == :from ::Date.new(year, month, 1) else ::Date.new(year, month, 1).end_of_month end when /^(\d\d?)[-\/](\d\d?)*$/ # Month-Day only month = $1.to_i day = $2.to_i unless [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].include?(month) raise ArgumentError, "invalid month number (1-12): '#{spec}'" end if spec_type == :from ::Date.new(today.year, month, day) else ::Date.new(today.year, month, day).end_of_month end when /\A(\d\d?)\z/ # Month only month = $1.to_i unless [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].include?(month) raise ArgumentError, "invalid month number (1-12): '#{spec}'" end if spec_type == :from ::Date.new(today.year, month, 1) else ::Date.new(today.year, month, 1).end_of_month end when /^(\d\d\d\d)$/ # Year only if spec_type == :from ::Date.new($1.to_i, 1, 1) else ::Date.new($1.to_i, 12, 31) end when /^(to|this_?)?day/ today when /^(yester|last_?)?day/ today - 1.day when /^(this_?)?week/ spec_type == :from ? today.beginning_of_week : today.end_of_week when /last_?week/ if spec_type == :from (today - 1.week).beginning_of_week else (today - 1.week).end_of_week end when /^(this_?)?biweek/ if spec_type == :from today.beginning_of_biweek else today.end_of_biweek end when /last_?biweek/ if spec_type == :from (today - 2.week).beginning_of_biweek else (today - 2.week).end_of_biweek end when /^(this_?)?semimonth/ spec_type == :from ? today.beginning_of_semimonth : today.end_of_semimonth when /^last_?semimonth/ if spec_type == :from (today - 15.days).beginning_of_semimonth else (today - 15.days).end_of_semimonth end when /^(this_?)?month/ if spec_type == :from today.beginning_of_month else today.end_of_month end when /^last_?month/ if spec_type == :from (today - 1.month).beginning_of_month else (today - 1.month).end_of_month end when /^(this_?)?bimonth/ if spec_type == :from today.beginning_of_bimonth else today.end_of_bimonth end when /^last_?bimonth/ if spec_type == :from (today - 2.month).beginning_of_bimonth else (today - 2.month).end_of_bimonth end when /^(this_?)?quarter/ if spec_type == :from today.beginning_of_quarter else today.end_of_quarter end when /^last_?quarter/ if spec_type == :from (today - 3.months).beginning_of_quarter else (today - 3.months).end_of_quarter end when /^(this_?)?half/ if spec_type == :from today.beginning_of_half else today.end_of_half end when /^last_?half/ if spec_type == :from (today - 6.months).beginning_of_half else (today - 6.months).end_of_half end when /^(this_?)?year/ if spec_type == :from today.beginning_of_year else today.end_of_year end when /^last_?year/ if spec_type == :from (today - 1.year).beginning_of_year else (today - 1.year).end_of_year end when /^forever/ if spec_type == :from ::Date::BOT else ::Date::EOT end when /^never/ nil else raise ArgumentError, "bad date spec: '#{spec}''" end end |