「1年365日君を愛してる」っていう歌に対して「それだと4年に1回愛してない日ができるのでマズいと思います」って言ったらうざがられるけど、プログラマの仕事においては大切な視点です
— yhara (Yutaka HARA) (@yhara) March 26, 2013
4年に1回じゃないです。400年に97回です。
— ゆかてん@太子さま復活祭 子22 (@yktn121162) March 26, 2013
うるう年の例外
例外がなければ、単純に4年に一日発生するので400年なら100日ですが…これが例外なんですね。単純に100回を365であまり求めちゃだめだっけ…? twitpic.com/ceho2h
— Renewed ぎたぱそ (@guitarrapc_fav) March 26, 2013
つまり、1700年は閏年だけど、1600年や2000年は閏年ではないと。 現在の西暦を、グレゴリオ暦として解釈した場合、Wiki上の閏年の定義は以下のようです。@guitarrapc_fav 100で割りきれる場合は閏年ではなく、ただし400で割りきれる場合は閏年だったような
— たなか (@tanaka_733) March 26, 2013
よって、400年周期で考えるべきであり、y00年(yが4の倍数以外) がうるう年でないため-3回かかると。
- 西暦年が4で割り切れる年は閏年
- ただし、西暦年が100で割り切れる年は平年
- ただし、西暦年が400で割り切れる年は閏年
.NETのIsLeapYear()メソッド
勿論ありました。MSDN - DateTime.IsLeapYear メソッドで、はぐれメタル先生からもアドバイスが。
これなら、true/falseで判定を返してくれるのですね。 ちなみに上記のコードは、trueで帰った数をwhere (?がAlias)で拾って、measureでカウントしています。 よって、閏年の件数が表示されます。@guitarrapc_fav 1..400|?{[datetime]::isleapyear($_)}|measure
— 牟田口大介 (@mutaguchi) March 26, 2013
Count : 97 Average : Sum : Maximum : Minimum : Property :
自分でも組んでみよう
当然、やってみたくなるわけです。条件式
閏年の判定条件式は、Cは以下のように組めます。(Wikiより)( year % 4 ) == 0 && ( year % 100 ) != 0 || ( year % 400 ) == 0PowerShellに置き換えるとこうです。
($_ % 4 -eq 0) -and !($_ % 100 -eq 0) -or ($_ % 400 -eq 0)基本的に、PowerShellの -or は、ショートサーキットなので置き換えるだけですね。
年と結果を返したい
どうせ作るなら、IsLeapYearとは違い、年と結果を纏めて返してくれると嬉しいです。 また、開始年と、終了念を渡すだけにできると嬉しいですね。 よって、このような感じで。function Get-LeapYear{ [CmdletBinding()] param( [parameter( mandatory=$true, ValueFromPipeLine=$true, ValueFromPipelineByPropertyName=$true)] [int]$YearBegin, [parameter( mandatory=$true, ValueFromPipeLine=$true, ValueFromPipelineByPropertyName=$true)] [int]$YearEnd ) Begin{ } Process{ switch($yearBegin..$yearEnd){ {($_ % 4 -eq 0) -and !($_ % 100 -eq 0) -or ($_ % 400 -eq 0)}{[PSCustomObject]@{Year=$_;Leap=$true};continue} default{[PSCustomObject]@{Year=$_;Leap=$false}} } } end{ } }利用する際は、これで。
Get-LeapYear -YearBegin 1600 -YearEnd 17001600年から1700年までの結果表示です。
Year Leap ---- ---- 1600 True 1601 False 1602 False 1603 False 1604 True 1605 False 1606 False 1607 False 1608 True 1609 False 1610 False 1611 False 1612 True 1613 False 1614 False 1615 False 1616 True 1617 False 1618 False 1619 False 1620 True 1621 False 1622 False 1623 False 1624 True 1625 False 1626 False 1627 False 1628 True 1629 False 1630 False 1631 False 1632 True 1633 False 1634 False 1635 False 1636 True 1637 False 1638 False 1639 False 1640 True 1641 False 1642 False 1643 False 1644 True 1645 False 1646 False 1647 False 1648 True 1649 False 1650 False 1651 False 1652 True 1653 False 1654 False 1655 False 1656 True 1657 False 1658 False 1659 False 1660 True 1661 False 1662 False 1663 False 1664 True 1665 False 1666 False 1667 False 1668 True 1669 False 1670 False 1671 False 1672 True 1673 False 1674 False 1675 False 1676 True 1677 False 1678 False 1679 False 1680 True 1681 False 1682 False 1683 False 1684 True 1685 False 1686 False 1687 False 1688 True 1689 False 1690 False 1691 False 1692 True 1693 False 1694 False 1695 False 1696 True 1697 False 1698 False 1699 False 1700 False勿論件数だけも出せます。400年の件数が97件か見てみましょう。 IsLeapYearと同じようにするだけですね。
Get-LeapYear -YearBegin 1500 -YearEnd 1900 | ?{$_.Leap} | measurePowerShell 3.0ならこうも書けます。
Get-LeapYear -YearBegin 1500 -YearEnd 1900 | ? Leap | measure結果です。
Count : 97 Average : Sum : Maximum : Minimum : Property :
結果のみ返したい
IsLeapYearと同じく、bool値でのみ返すならこうですね。function Get-IsLeapYear{ [CmdletBinding()] param( [parameter( mandatory=$true, ValueFromPipeLine=$true, ValueFromPipelineByPropertyName=$true)] [int]$YearBegin, [parameter( mandatory=$true, ValueFromPipeLine=$true, ValueFromPipelineByPropertyName=$true)] [int]$YearEnd ) Begin{ } Process{ switch($yearBegin..$yearEnd){ {($_ % 4 -eq 0) -and !($_ % 100 -eq 0) -or ($_ % 400 -eq 0)}{$true;continue} default{$false} } } end{ } }利用時はこうです。
Get-IsLeapYear -YearBegin 1900 -YearEnd 1920true/falseが返ってきます。
False False False False True False False False True False False False True False False False True False False False Trueこれは、.NETのIsLeapYearと同様です。
1900..1920 | %{[Datetime]::IsLeapYear($_)}true/falseが返ってきます。
False False False False True False False False True False False False True False False False True False False False True勉強になりました。