67
\$\begingroup\$

Basing on this SO question.

Challenge is rather simple: given a date period in the format YYYYMM output it in the format MMMYY.

Rules:

  • The input will be a number or a string exactly 6 characters long, consisting only of digits.
  • Last two digits will be between 01 and 12.
  • Output must be in the form MMMYY, where MMM represents uppercase three-letter code for the month (below) and YY represents two last digits of the YYYY part of the input.

List of months with corresponding code:

MM    MMM
01    JAN
02    FEB
03    MAR
04    APR
05    MAY
06    JUN
07    JUL
08    AUG
09    SEP
10    OCT
11    NOV
12    DEC

Examples:

Input     Output
201604    APR16
200001    JAN00
000112    DEC01
123405    MAY34
\$\endgroup\$
2
  • 6
    \$\begingroup\$ This question is very well-balanced. Both manual parsing and date libraries end up being about the same, at least in Python. \$\endgroup\$
    – jqkul
    Jun 22, 2016 at 20:32
  • 13
    \$\begingroup\$ Yesterday, I saw "Convert YYYYMM to MMMYY" on HNQ beside the SO logo. Now I see the same title beside the PCG logo. I was very confused :) \$\endgroup\$
    – cat
    Jun 23, 2016 at 14:30

65 Answers 65

1
\$\begingroup\$

J, 70 bytes

4(}.((,~(_3]\'JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'){~1-~".)~2&}.){.)]

Usage

   f =: 4(}.((,~(_3]\'JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'){~1-~".)~2&}.){.)]
   f '201604'
APR16
   f '200001'
JAN00
   f '000112'
DEC01
   f '123405'
MAY34

Explanation

4(}.((,~(_3]\'...'){~1-~".)~2&}.){.)] Input: s
                                    ] Identity function, gets the value s
4                                     The constant 4
                                 {.   Take the first 4 chars from s
                            2&}.      Drop the first 2 (Take the last 2) to get the year
  }.                                  Drop the first 4 chars from s to get the month
                        ".            Parse the month substring as a number
                     1-~              Subtract 1 from it
             '...'                    List of MMM month names
         _3]\                         Split the list into nonoverlapping sublists of size 3
      ,~                              Join the MMM month name with the year and return
\$\endgroup\$
1
\$\begingroup\$

Pyth, 39 bytes

Hexdump:

0000000: 2b 40 63 2e 22 41 59 12 56 0a 7c bd 93 e3 1c 07 +@c."AY.V.|.....
0000010: e3 d4 d9 ed 5b 49 02 cd b4 92 83 86 22 33 73 3e ....[I......"3s>
0000020: 32 7a 3a 7a 32 20 34                            2z:z2 4

Test suite.

\$\endgroup\$
1
\$\begingroup\$

jq, 35 characters

(34 characters code + 1 character command-line option.)

(Just tried whether the ^ trick used by Digital Trauma in his Bash answer works in jq too. Works. Now you know who inspired the most important character of this answer. (The alternative is to use the ascii_upcase function.))

strptime("%Y%m")|strftime("%^b%y")

Sample run (Option -R used only in this sample to pass all test cases.)

bash-4.3$ jq -Rr 'strptime("%Y%m")|strftime("%^b%y")' <<END
201604
200001
000112
123405
END
APR16
JAN00
DEC01
MAY34

On-line test: (Passing -R through URL is not supported – so input passed as JSON string literal. Passing -r through URL is not supported – check Raw Output yourself.)

\$\endgroup\$
1
\$\begingroup\$

Factor, 82 78 bytes

[ [ 2 tail* 10 base> month-abbreviation ] [ 4 head 2 tail ] bi append >upper ]

Eshplained:

[                    ! new anonymouse function block (quotation)
  [                  ! new quotation 
    2 tail*          ! "201604" -> "04"
    10 base>         ! "04"     -> 4
    month-abbreviation ! 4 -> "Apr"
  ]                  ! end quotation
  [                  ! new quotation
    4 head           ! "201604" -> "2016"
    2 tail           ! "2016"   -> "16" 
  ]                  ! end quotation
  bi                 ! bifurcate two quotations to TOS
  append             ! "Apr" "16" -> "Apr16"
  >upper             ! "Apr16"    -> "APR16"
]                    ! end quotation
\$\endgroup\$
1
\$\begingroup\$

PHP, 78 bytes

<?=fscanf(STDIN,"%4d%d",$y,$m)?strtoupper(date("My",mktime(0,0,0,$m,1,$y))):0;

The "year 2038 problem" may occur on some computers, as here. But not in others, as here.

\$\endgroup\$
1
  • \$\begingroup\$ @Titus, please don't try to edit other peoples' posts if there are problems and insert your own solutions; instead, please comment on the answer OR create a new answer yourself. \$\endgroup\$
    – Value Ink
    Jun 25, 2016 at 7:32
1
\$\begingroup\$

Swift 2.2, 149 bytes

let f = NSDateFormatter(),g = NSDateFormatter();f.dateFormat = "yyyyMM";g.dateFormat = "MMMyy"
g.stringFromDate(f.dateFromString(i)!).uppercaseString

Trying to get this shorter than Kotlin... It's a shame NSDateFormatter doesn't have an initializer that sets its dateFormat. NSDateFormatter also does not have a default dateFormat value, causing additional losses.

Swift 3, 136 bytes

let f = DateFormatter(),g = DateFormatter();f.dateFormat = "yyyyMM";g.dateFormat = "MMMyy"
g.string(from: f.date(from: i)!).uppercased()

Thanks to the removal of the NS prefix on some classes, I was able to make the Swift 3 answer a little shorter. Still not shorter than Kotlin though...

Test function and cases:

import Foundation
import XCTest

func dateConverter(i: String) -> String? {
    let f = DateFormatter(),g = DateFormatter();f.dateFormat = "yyyyMM";g.dateFormat = "MMMyy"

    if let date = f.date(from: i) {
        return g.string(from: date).uppercased()
    }

    return nil
}

XCTAssert(dateConverter(i: "201604") == "APR16")
XCTAssert(dateConverter(i: "200001") == "JAN00")
XCTAssert(dateConverter(i: "000112") == "DEC01")
XCTAssert(dateConverter(i: "123405") == "MAY34")
\$\endgroup\$
1
  • \$\begingroup\$ Don’t you have to import Foundation in Swift 3? I’ve never used Swift 3 seriously, but I know you need that in Swift 5 at least. \$\endgroup\$
    – Bbrk24
    Jun 22, 2023 at 17:33
1
\$\begingroup\$

R, 154 150 114 112 bytes

Takes six digit input into "b", separates the first four digits from the last two digits, abbreviates the 2-digit month and makes it uppercase, and concatenates it with the 3rd and 4th digit.

Golfed:

function(b){h=substr;i=sprintf;o="%06d";cat(toupper(month.abb[as.numeric(h(i(o,b),5,6))]),h(i(o,b),3,4),sep="")}

Ungolfed:

function(b){
   h=substr;i=sprintf;o="%06d";

   cat(
      toupper(month.abb[as.numeric(h(i(o,b),5,6))]),
      h(i(o,b),3,4),
   sep="")
}

EDITS: replaced duplicitous names with variables; fixed me being stupid. -2 bytes by turning function anonymous (thanks, cat).

\$\endgroup\$
8
  • \$\begingroup\$ Nice answer! You can leave off the a= for an anonymous function \$\endgroup\$
    – cat
    Jun 24, 2016 at 17:56
  • \$\begingroup\$ @cat I'm not too familiar with anonymous functions but wouldn't I need to add parentheses at the beginning and end of the function if I removed the a= ? Something like this: (function(m) {a=3;m*a})(10) \$\endgroup\$ Jun 24, 2016 at 18:52
  • 1
    \$\begingroup\$ Nope, function(b){h=substr;i=sprintf;o="%06d";cat(toupper(month.abb[as.numeric(h(i(o,b),5,6))]),h(i(o,b),3,4),sep="")} is a function object all on its own. \$\endgroup\$
    – cat
    Jun 24, 2016 at 19:17
  • \$\begingroup\$ This doesn't appear to work. on RStudio with R 3.2.3 (2015-12-10) I get Error in i(o, b) : invalid format '%06d'; use format %s for character objects \$\endgroup\$
    – cat
    Jun 24, 2016 at 19:18
  • \$\begingroup\$ @cat Darn new versions messing everything up! I'm on RStudio running R version 3.1.1 (2014-07-10) and it works fine. How does this work here, should I get the new version and change up the code? Also thanks for the anonymous function tip! \$\endgroup\$ Jun 24, 2016 at 19:44
1
\$\begingroup\$

SmileBASIC, 85 bytes

DEF C D?MID$(@__JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC,VAL(D[4]+D[4])*3,3);D[2];D[3]END

@__JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC is equivalent to the string literal "@__JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC". JAN starts at index 3, so the program can calculate the position as month*3 instead of (month-1)*3 or month*3-3.

\$\endgroup\$
1
\$\begingroup\$

C# - 75 Bytes

s=>{return new System.DateTime(s/100,s%100,1).ToString("MMMyy").ToUpper();}
\$\endgroup\$
1
\$\begingroup\$

K4, 65 59 bytes

Solution:

@[13 3#"DECJANFEBMARAPRMAYJUNJULAUGSEPOCTNOV";.*|x],*x:2 4_

Examples:

q)k)@[13 3#"DECJANFEBMARAPRMAYJUNJULAUGSEPOCTNOV";.*|x],*x:2 4_"201604"
"APR16"
q)k)@[13 3#"DECJANFEBMARAPRMAYJUNJULAUGSEPOCTNOV";.*|x],*x:2 4_"200001"
"JAN00"
q)k)@[13 3#"DECJANFEBMARAPRMAYJUNJULAUGSEPOCTNOV";.*|x],*x:2 4_"000112"
"DEC01"
q)k)@[13 3#"DECJANFEBMARAPRMAYJUNJULAUGSEPOCTNOV";.*|x],*x:2 4_"123405"
"MAY34"

Explanation:

Reshape the months of the year so that 0 => DEC and 1 => JAN ... 12 => DEC.

@[13 3#"DECJANFEBMARAPRMAYJUNJULAUGSEPOCTNOV";.*|x],*x:2 4_ / the solution
                                                       2 4_ / cut input at indices 2 & 4, "201604" => ["16", "04"]
                                                     x:     / save as x
                                                    *       / take first
                                                   ,        / join with
@[                                           ;    ]         / apply @[list;index]
                                               *|x          / reverse (|), first (*) aka 'last'
                                              .             / value ("05" => 5)
       "DECJANFEBMARAPRMAYJUNJULAUGSEPOCTNOV"               / offset months of the year
  13 3#                                                     / reshape

Bonus:

60 byte version in K (oK):

((13 3#"DECJANFEBMARAPRMAYJUNJULAUGSEPOCTNOV")@.*|x),*x:2 4_

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Caché ObjectScript - 65 bytes

Golfed

r i s d=$zcvt($zd($zdth(i_"01",8),6),"u") w $e(d,1,3)_$e(d,*-1,*)

Ungolfed

r i                            ; Read stdin and store into 'i'                      [200203]
   s d=                        ; Set the variable 'd' to the following...
       $zcvt(                  ; Convert the string
             $zd(              ; Parse the string as a caché date
                 $zdth(        ; Convert the date to horolog format (# days from 12/31/1840)
                       i_"01", ; Append the string "01" to variable 'i'             [20020301]
                       8       ; Use format #8 - "YYYYMMDD" (e.g. 20020301)
                      ),                                                            [58864,0]
                 6             ; Use format #6 - "Mmm [D]D YYYY" (e.g. Mar 1 2002)
                ),                                                                  [Mar 1 2002]
             "u"               ; Convert the string to uppercase
            )                                                                       [MAR 1 2002]
   w                           ; Write out the following...
     $e(d,1,3)                 ; Extract the substring from position 1 to 3 (inclusive) [MAR]
     _                         ; Concatenate
     $e(d,                     ; Extract the substring...
        *-1,                   ; ...from 1 character from the end of the string     [0]
        *                      ; ...to the last character                           [2]
       )                                                                            [02]
                                                                                    [MAR02]

Commentary

I don't think I've ever seen another Caché answer on this site. I'm only forced to know the language because of work (legacy code), but language itself is very powerful.

Some notes about the language:

  • Caché doesn't really care about whitespace, so r x r y is the same as r x \n r y
  • Each function is the shortname for the longer version:
    • r == read
    • s == set
    • $zcvt == $zconvert
    • $zd == $zdate
    • $zdth == $zdateh
    • $e == $extract
  • Arrays are 1-indexed

Unfortunately, there is no online interpreter for Caché. Probably either because it's too obscure or maybe a licensing thing.

If you're interested in the language, you can check out their docs on their very 90's looking website :)

\$\endgroup\$
1
\$\begingroup\$

PHP, 146 Bytes.

Manipulating string

Code Try it online

function f($d){echo strtr(ltrim(substr($d,-2),'0'),array_combine(range(1,12),
str_split(JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC,3))).substr($d,2,-2);}

Explanation

function f($d){
                                #strtr allows u to set an array to replace the ocurrences
echo strtr(ltrim(substr($d,-2),'0'),        #Substring of the last two numbers of the input, 
                                           #removing leading zero
    array_combine(range(1,12),      
    str_split(JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC,3)))
                                           #create an array of ["1"=>JAN, "2"=>FEB...12=>DEC], 
                                           #split the string by 3 characters
    .substr($d,2,-2);
                                           #Concatenate the 2 middle characters
}
\$\endgroup\$
1
\$\begingroup\$

JavaScript ES6, 61 bytes

@Downgoat seems not there so I repost to optimize

a=>(new Date(0,a%100-1)+0).slice(4,7).toUpperCase()+a[2]+a[3]

\$\endgroup\$
1
\$\begingroup\$

C (tcc), 155 bytes

Longest answer here.

main(i){char*k,s[6],*a="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";gets(s);strcpy(k,s+2);memset(k+2,0,2);i=atoi(s+4)*3;memset(a+i,0,i);strcat(k,a+i-3);puts(k);}

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Welcome to PPCG! :) \$\endgroup\$
    – Shaggy
    Jul 20, 2018 at 14:51
  • \$\begingroup\$ 136 bytes \$\endgroup\$
    – ceilingcat
    Aug 20, 2019 at 0:32
1
\$\begingroup\$

C (gcc), 107 104 bytes

main(){char s[7];gets(s+1);write(1,memcpy(s,"JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"+~-atoi(s+5)*3,3),5);}

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Pyth, 42 bytes

Ac2>Q2+@c12."AY4H~0ë™~³!ò²×Œ¶7Ö"tiHTG

Try it online!

Ac2>Q2+@c12."AY4H~0ë™~³!ò²×Œ¶7Ö"tiHTG   // With Input '123405'

   >Q2                                       // Get input from index 2 (3405)
Ac2 ^                                        // Split it in two and assign to G and H (G='34', H='05'])
           ."AY4H~0ë™~³!ò²×Œ¶7Ö"             // Packed string representing: "JANFEBMAR..."
        c12."    JANFEBMAR...     "        // Chop it into 12 pieces (["JAN", "FEB", "MAR"...])
                                     tiHT    // Convert "05" to 5, subtract 1.
       @  ["JAN", "FEB", "MAR"...]   tiHT    // Get element at that index (MAY)
      +           "MAY"                  G   // "MAY" + 34
\$\endgroup\$
1
\$\begingroup\$

Groovy, 69 55 51 bytes

f={sprintf('%Tb',(it[4..5]as int)*22**7L)+it[2..3]}

Try it online!

This formats a millisecond value as an uppercase month name: sprintf('%Tb',value). The magic value of 22^7 is a value such that n * 22^7 milliseconds after epoch is in the nth month of the year of 1970. This value was derived by testing all possible 1 to 2 digit values. Therefore month * 22^7 will yield a value within that month.

  1. 1970-01-29
  2. 1970-02-27
  3. 1970-03-28
  4. 1970-04-26
  5. 1970-05-25
  6. 1970-06-23
  7. 1970-07-22
  8. 1970-08-19
  9. 1970-09-17
  10. 1970-10-16
  11. 1970-11-14
  12. 1970-12-13
\$\endgroup\$
1
\$\begingroup\$

Haskell, 85 bytes

f s=3`take`drop(read(drop 4s)*3-3)"JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"++[s!!2,s!!3]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Vyxal o, 37 bytes

4ȯI«×g~Þ¯p-Ḃ:u‹Ẇ¹²Ṗ¨€r;↓§%«3ẇ$‹i⇧₴4Ẏ∷

Try it Online!

4ȯI                # Month as int
   «...«3ẇ         # Compressed string of month names
          $‹i      # Get the correct month
             ⇧₴    # Uppercase and print
               4Ẏ∷ # Get the last two digits of year
\$\endgroup\$
1
\$\begingroup\$

Lua 5.3, 82 bytes

i=io.read()print(os.date("%b%y",os.time({year=i//100,month=i%100,day=1})):upper())

Needs to be run on an english machine, as the month name is language specific.

Version that works in any locale 91 bytes

i=io.read()j=i%100*3 print(("JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"):sub(j-2,j)..i:sub(3,4))
\$\endgroup\$
1
  • \$\begingroup\$ %100 can be %20 \$\endgroup\$
    – Jo King
    Jun 22, 2023 at 4:27
1
\$\begingroup\$

Scala, 85 bytes

s=>"JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC".drop(30*s(4)+3*s(5)-1587).take(3)+s(2)+s(3)

The index lookup 30*s(4)+3*s(5)-1587 is a golfed version (via ASCII arithmetics) of the more readable s.slice(4,6).toInt*3-3.

Try it online!

I also tried the nice trick by @cliffroot to represent the names of the months via Chinese characters. This gives the following variant that is 23 characters shorter (62 instead of 85), but at the end 1 byte longer (86 instead of 85):

s=>""+BigInt(""+"憯䷳烣㘿烪摿摽㛨近筍矯䏔"(10*s(4)+s(5)-528),36)+s(2)+s(3)

\$\endgroup\$
1
\$\begingroup\$

Factor, 56 bytes

[ 2 tail 2 cut dec> months "%b"strftime >upper prepend ]

Try it online!

Explanation

          ! "201604"
2         ! "201604" 2
tail      ! "1604"
2         ! "1604" 2
cut       ! "16" "04"
dec>      ! "16" 4
months    ! "16" T{ duration f 0 4 0 0 0 0 }
"%b"      ! "16" T{ duration f 0 4 0 0 0 0 } "%b"
strftime  ! "16" "Apr"
>upper    ! "16" "APR"
prepend   ! "APR16"
\$\endgroup\$
1
\$\begingroup\$

Python, 115 bytes

m='JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC'.split();d=input();print("%s%s"%(m[int(d[4]+d[5])-1],d[2]+d[3]))

Try it online

\$\endgroup\$
1
  • \$\begingroup\$ I suggest that you look into lambda functions and generally try to avoid use of split() - That said, I think that JQBLZ's manual string parsing answer may already be optimal for Py3 - you should take a look at that one \$\endgroup\$ Feb 6, 2022 at 21:13
1
\$\begingroup\$

Thunno 2, 32 bytes

²ẸN“¤ɼḋġŀ§P¡^Ȥḥ)ñt:²æṆµṖƒr“R³İs+

Attempt This Online!

Explanation

²ẸN“...“R³İs+    # Implicit input        ->  "123405"
²                # Split into pairs      ->  ["12","34","05"]
 Ẹ               # Dump onto stack       ->  "12", "34", "05"
  N              # Cast to integer       ->  "12", "34", 5
   “...“         # Compressed string     ->  "12", "34", 5, "janfeb...novdec"
        R        # Uppercase it          ->  "12", "34", 5, "JANFEB...NOVDEC"
         ³       # Split into threes     ->  "12", "34", 5, ["JAN",...,"DEC"]
          İ      # One-based indexing    ->  "12", "34", "MAY"
           s+    # Swap and concatenate  ->  "12", "MAY34"
                 # Implicit output       ->  "MAY34"
\$\endgroup\$
1
\$\begingroup\$

Go, 107 bytes

import(."time";."strings")
func f(s string)string{t,_:=Parse("200601",s)
return ToUpper(t.Format("Jan06"))}

Attempt This Online!

I wish Go's time formatting strings allowed all caps months like JAN06; that would save 22 bytes.

\$\endgroup\$
0
\$\begingroup\$

Batch, 148 bytes

@set d=%1
@for %%m in (JAN.01 FEB.02 MAR.03 APR.04 MAY.05 JUN.06 JUL.07 AUG.08 SEP.09 OCT.10 NOV.11 DEC.12)do @if %%~xm==.%d:~4% echo %%~nm%d:~2,2%

No date libraries to speak of so manual parsing ftw. I don't know whether the rules of Code Golf allow creating 12 appropriately-named files in the current directory, resulting in something like this:

@set d=%1
@for %%m in (*.%d:~4%)do @echo %%~nm%d:~2,2%
\$\endgroup\$
0
\$\begingroup\$

Ruby 46 + 6 for -rdate = 52

For completeness, if nothing else.

->d{Date.strptime(d,'%Y%m').strftime('%^b%y')}

See the tests on repl.it: https://repl.it/Cj7z

\$\endgroup\$
2
  • \$\begingroup\$ The closest I could get without rdate was 70 bytes, so this looks like the winning tactic for Ruby. \$\endgroup\$
    – benj2240
    Apr 6, 2018 at 20:12
  • \$\begingroup\$ -6? \$\endgroup\$ Feb 6, 2022 at 4:29
0
\$\begingroup\$

T-SQL, 96 bytes

declare @i varchar(8)
select  @i = '201604'
select upper(left(datename(month,@i+'01'),3)) + substring(@i,5,2)
\$\endgroup\$
0
\$\begingroup\$

Java, 142 bytes

s->(new String[]{"JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"})[Integer.decode(s.substring(4))-1]+s.substring(2,4);
\$\endgroup\$
0
\$\begingroup\$

dc, 103 bytes

[0n]sP[JAN][FEB][MAR][APR][MAY][JUN][JUL][AUG][SEP][OCT][NOV][DEC]Csi[lid1-si:mz1<M]dsMxA0~;mPA0~dZ2>Pp

Try it online!

[0n]sP is a macro that just prints a 0 w/o a newline for the sake of padding 1-9.

[JAN]...[DEC] places the strings on the stack. Csi[lid1-si:mz1<M]dsMx is a macro that decrements i from 12, popping the strings off of the stack and placing them at index i in the array m. Stops when one item (input) is left on the stack.

100~;mP does quotient/remainder division by 100, and prints the value from m indexed by the remainder. The quotient is left on the stack. 100~dZ2>Pp again gets the remainder after dividing by 100, runs the padding macro P this is one digit long, and then prints.

Without any way of manipulating strings, I don't think that part is golfable. Doing any sort of wizardry with JAN/JUN/JUL would likely take far more bytes than the strings themselves.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.