10
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

DATEDIFFもどきを作る|Power Query

Last updated at Posted at 2019-10-08

2020/9/7更新:バージョン2のコードを修正しました。
2020/2/11更新:エラー出しや引数のドロップダウン等に対応したバージョンを追加しました。
公式関数にないものの、Power Query内で処理するなら、経過年月が必要になることもあります。
個人的には月数が出したいので、作ってました。

##コード
引数のintervalにはy,m,dの3種類を入れるか、もしくは省略してください。
インターバルを入れない場合は、年・月・日の3種類それぞれのベースでの結果を返す仕様にしてみました。
要らないかな。:expressionless:
※クリックすると開きます。

コード1
(date1 as date,date2 as date,optional interval as text)=>

//check the argument―"interval"
if List.Contains({"y","m","d",null},interval) then

    let 
        Difference =[Year =Date.Year(date2)-Date.Year(date1),
                     Month =Date.Month(date2)-Date.Month(date1),
                     day =Date.Day(date2)-Date.Day(date1)],

        MonthAdjustment= if Difference[day]<0 then -1 else 0,

        Answers =[
                  d = Duration.Days(date2-date1),
                  m = Difference[Year]*12+Difference[Month]+MonthAdjustment,
                  y = Difference[Year]
                      +(if (Difference[Month]+MonthAdjustment) <0 then -1 else 0)
                 ],
   
        Answer = if interval =null then Answers
                 else Record.Field(Answers,interval)
    in
        Answer

else "intervalはy,m,dのいずれかを指定するか、省略してください。"

##メモ

  • 「日」単位以下は、Duration関数群があるので、そちらを使いましょう。
  • githubなどにもいくつか作例が出ていたはずです。
  • DAXの方にはDATEDIFF関数があります。
  • プルダウンで引数を選択させられれば最高ですが、そもそもできるかどうか分からなかったので、ifでエラー回避しました。

##追記分
勉強がてら、手を入れました。コードが長いですが、半分くらいは設例等によるものです。
なお、Excelのワークシート同様、想定外の引数が入った場合にはエラー処理するように修正しました。
###コード2(強化版)

fx_DateDiff_PQ
let
    BodyOfFunction=    
    (date1 as date,date2 as date, optional interval as text)=>
    let 
        Difference =[Year =Date.Year(date2)-Date.Year(date1),
                     Month =Date.Month(date2)-Date.Month(date1),
                     day =Date.Day(date2)-Date.Day(date1)],
        MonthAdjustment= if Difference[day]<0 then -1 else 0,
        Answers =[
                  d = Duration.Days(date2-date1),
                  m = Difference[Year]*12+Difference[Month]+MonthAdjustment,
                  y = Difference[Year]
                      +(if (Difference[Month]+MonthAdjustment) <0 then -1 else 0)
                 ],
        Answer = if (date1<=date2) and List.Contains({"y","m","d",null},interval) then
                    if interval =null then Answers
                    //2020/9/7修正
                    else  Record.Field(Answers,interval)
                 else ...
    in
        Answer,

    //3番目の引数に係るドロップダウンリストを定義
    IntervalType =type text
                      meta [Documentation.AllowedValues = {"y","m","d"}],

    //関数自体の説明書き,設例
    NewFunctionType =type function(date1 as date,date2 as date, optional interval as IntervalType) as any
                        meta[Documentation.Name ="fx_DateDiff_PQ",
                             Documentation.LongDescription=
                                    "<code>date1</code>から<code>date2</code>の期間に係るデータを取り出します。"
                                  & "<code>interval</code>を省略した場合は、年月日の3種類すべての結果をレコードで返します。",
                             Documentation.Examples=
                                    {
                                         [
                                          Description="2019/12/29から2020/2/29の月数を求めます。日の部分が同じため丁度2か月扱いとなります。",
                                          Code ="fx_DateDiff_PQ(#date(2019,12,29),#date(2020,2,29),""m"")",
                                          Result ="2"
                                         ],
                                         [
                                          Description="2019/12/29から2020/2/29の期間情報を求めます。<code>interval</code>を省略します。",
                                          Code ="fx_DateDiff_PQ(#date(2019,12,29),#date(2020,2,29))",
                                          Result ="[d=62,m=2,y=0]"
                                         ]

                                    }
                            ],
    ReplaceType =Value.ReplaceType(BodyOfFunction,NewFunctionType)
in
    ReplaceType

###出来上がりの様子
強化版の関数は、詳細エディタに貼るとこんな感じになります。
image.png

###注
ドロップダウンはUI上の話だけで、そこに規定してない値も受け入れができてしまいます。
そのため、ドロップダウン処理とは別に、エラーを出すように仕向けています。
エラーメッセージは、また今度ということで。

###参考
Writing documentation for custom M-functions, Part1 | THE SELF-SERVICE-BI BLOG

Chris Webb's BI Blog: Specifying Allowed Values, Sample Values and Descriptions For Function Parameters In Power Query–Part 1 Chris Webb's BI Blog

10
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?