Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Why is this -monthly("201901","YM")- not working, while this -date("20190101","YMD")- works perfectly fine?

    In my opinion this should be working:

    Code:
    . dis %tm monthly("201901", "YM")
          .
    but it is not working, it returns a missing value.

    Then this is working, while in my opinion it should not be working:

    Code:
    . dis %td date("201901", "YM")
    01jan2019
    And finally this is working as it should, and I know how to use this fact to resolve the problem above:

    Code:
    . dis %tm mofd(date("20190101", "YMD"))
     2019m1
    My question is: Is the the behavour of -monthly- a bug that I should report to Stata Corp? Or am I doing something wrong and -monthly- can be made work if used in some more appropriate way?

  • #2
    This has been noted before. monthly() isn't as smart as daily(). numdate (SSC) has an extra parsing step to try to cope.


    Code:
    clear 
    input str6 probdate 
    200901 
    end 
    
    numdate monthly mdate=probdate, pattern(YM) 
    
    list 
    
         +-------------------+
         | probdate    mdate |
         |-------------------|
      1. |   200901   2009m1 |
         +-------------------+

    Comment


    • #3
      Thank you Nick, this -numdate- looks cool, in particular it is nice that it seems to give the same procedure whether you start from a date formulated as a string, or as a number.

      For the time being I would like to do this "best way" and without using extra packages.

      So if I start with the number 20190101, I would firstly convert to string, and then use -date-.

      But as -monthly- is not as smart, this does not lead to anything nice.

      So does it sound to you a good idea if I starting from number 201901, I do not translate to string first, but rather work with numerical components like that


      Code:
      dis %tm ym(floor(201901/100), mod(201901,100))
       2019m1
      Do you see any nicer way to achieve this?

      Comment


      • #4
        Apparently this has to do with how dates are encoded, but I don't know why it works like this. Specifically, date-time strings in human-readable format (so-called HRFstr in Stata documentation) are required for date translation functions like monthly, daily, etc. This is further discussed in -help datetime translation-.

        If you draw your attention to specifying the mask (-help datetime_translation##mask-), you will see the full range of date-time masks accepted. What was not explicitly outlined in the help, and took a bit of fiddling, was that when using the -monthly()- function, one may only specify masks with month and year ("YM", "MY").

        For example, "01dec2006 14:22" is in an accepted format, matching the mask "DMYhm". When we try it with monthly, it fails.

        Code:
        di monthly("01dec2006 14:22", "MY")
        .
        However, if you only keep the month and year portion, stripping away the day of month and time, then it works. Here are some examples.

        Code:
        . di monthly("dec2016", "MY")
        683
        
        . di monthly("2016m12", "YM")
        683
        
        . di monthly("16m12", "YM", 2100)
        683
        
        . di monthly("December 2016", "MY")
        683
        
        . di monthly("Dec 2016", "MY")
        683
        
        . di monthly("2016-12", "YM")
        683
        
        . * puzzlingly, this doesn't work
        . di monthly("201612", "YM")

        Comment


        • #5
          #3 I've often posted here and elsewhere similar solutions using floor() and mod().

          numdate and its siblings were an attempt to provide something more systematic. They haven't attracted much interest. But my impression from discussions with StataCorp developers is that there is a long-term awareness that dates need to be made a bit more friendly, but some of that needs to include hits on code for functions, which users cannot do.

          Experienced users manage to solve >>90% of the problems by reading the documentation, which some users seem to be unwilling to do.

          Comment


          • #6
            Leonardo, your by trial and error observation that

            Code:
             
             . di monthly("2016-12", "YM") 683
            works, suggests a solution. Not particularly elegant, but a solution nevertheless:

            Code:
            . dis %tm monthly(substr("201901",1,4)+"-"+substr("201901",5,6), "YM")
             2019m1

            Comment


            • #7
              Originally posted by Nick Cox View Post
              #3 I've often posted here and elsewhere similar solutions using floor() and mod().

              numdate and its siblings were an attempt to provide something more systematic. They haven't attracted much interest. But my impression from discussions with StataCorp developers is that there is a long-term awareness that dates need to be made a bit more friendly, but some of that needs to include hits on code for functions, which users cannot do.

              Experienced users manage to solve >>90% of the problems by reading the documentation, which some users seem to be unwilling to do.
              Thank you for confirming that the solution in # is considered good practice code, because I am already going around recommending it to other people
              https://www.statalist.org/forums/for...t-stock-return

              Otherwise this certainly is not something that I have come up with, I have certainly seen the use of the mod() function from you.

              In my old code, say from a couple of years ago, I used to accomplish the task in #3 through the int() function, but for some reason this does not work now when in one step. It works if I split it in two steps:

              Code:
              . dis %tm ym(int(201901/100), 100*(201901/100-int(201901/100)))
                    .
              
              . dis 100*(201901/100-int(201901/100))
              1
              
              . dis %tm ym(int(201901/100), 1)
               2019m1




              Comment


              • #8
                When confronted with a six-character string YM variable, consider the following approach which doesn't involve math or substring, based on Joro's post #1.
                Code:
                . generate ymn = mofd(date(yms+"01", "YMD"))
                
                . format %tm ymn
                
                . list, clean noobs
                
                       yms      ymn  
                    201906   2019m6

                Comment


                • #9
                  Originally posted by William Lisowski View Post
                  When confronted with a six-character string YM variable, consider the following approach which doesn't involve math or substring, based on Joro's post #1.
                  Code:
                  . generate ymn = mofd(date(yms+"01", "YMD"))
                  
                  . format %tm ymn
                  
                  . list, clean noobs
                  
                  yms ymn
                  201906 2019m6
                  William, your code is the sounds thing to do, which is expected to work, and does work...

                  To my shock the following thing which is not sound at all, and as expected does not work in Stata 11, for some mysterious reason starts to work from Stata 12 up to Stata 15:

                  Code:
                  . generate ymn = mofd(date(yms, "YM"))
                  
                  . format ymn %tm
                  
                  . list , clean
                  
                            yms      ymn  
                    1.   201906   2019m6
                  So as it turns out, the proper code that you are showing is not even necessary, because the improper code just above mysteriously works.

                  Comment

                  Working...
                  X