Коротка дата на англійській мові Long Date


14

Перетворіть короткий формат дати в англійську довгу дату якомога менше байтів.

Вхідні дані

Введення буде у формі рядка з форматом yyyy-mm-dd, з додатковою нульовою підкладкою для всіх значень. Ви можете припустити, що це синтаксично правильно, але не обов'язково є дійсною датою. Негативні значення року не потрібно підтримувати.

Вихідні дані

Ви повинні перетворити дату в англійський формат довгої дати (наприклад 14th February 2017). Нульові прокладки тут заборонені.

Якщо дата є недійсною (наприклад 2011-02-29), то її необхідно визнати певним чином. Накидання винятку дозволено.

Більше прикладів можна побачити нижче.

Випробування

"1980-05-12" -> 12th May 1980
"2005-12-3"  -> 3rd December 2005
"150-4-21"   -> 21st April 150
"2011-2-29"  -> (error/invalid)
"1999-10-35" -> (error/invalid)

5
Чи дозволено набивання нуля? ака 03rdзамість3rd
чорнило вартості

@ValueInk Якщо ви читаєте мій попередній коментар, ігноруйте його; Я неправильно зрозумів питання. Нульові прокладки у виході заборонені.
GarethPW

Чи слід розглядати рік, який містить більше 4-х символів (наприклад, 10987-01-01)?
mdahmoune

@mdahmoune Вам не потрібно підтримувати це, якщо це не простіше зробити.
GarethPW

Про що 2016-2-29?
Олів'є Грегоар

Відповіді:


5

PostgreSQL, 61 символ

prepare f(date)as select to_char($1,'fmDDth fmMonth fmYYYY');

Підготовлений оператор, приймає введення як параметр.

Проба зразка:

Tuples only is on.
Output format is unaligned.
psql (9.6.3, server 9.4.8)
Type "help" for help.

psql=# prepare f(date)as select to_char($1,'fmDDth fmMonth fmYYYY');
PREPARE

psql=# execute f('1980-05-12');
12th May 1980

psql=# execute f('2005-12-3');
3rd December 2005

psql=# execute f('150-4-21');
21st April 150

psql=# execute f('2011-2-29');
ERROR:  date/time field value out of range: "2011-2-29"
LINE 1: execute f('2011-2-29');
                  ^
psql=# execute f('1999-10-35');
ERROR:  date/time field value out of range: "1999-10-35"
LINE 1: execute f('1999-10-35');
                  ^
HINT:  Perhaps you need a different "datestyle" setting.

Приємно, побажання MS-SQL визнав "й" стиль форматування.
BradC

Враховуючи, що вам вдалося виконати завдання належним чином з найменшими байтами, я вважаю, що ваше рішення є переможцем!
GarethPW

Ого. Спасибі. Це абсолютно несподівано. Досі не помічала відсутності спеціальних мов для гольфу. Однак прийняття рішення лише через один день скоро.
манатура

@manatwork Мені було цікаво, чи це може бути трохи рано. Але я можу це змінити, якщо це все одно буде потрібно.
GarethPW

7

Python 3.6, 137 129 байт

from datetime import*
def f(k):g=[*map(int,k.split('-'))];n=g[2];return f"{date(*g):%-d{'tsnrhtdd'[n%5*(n^15>4>n%10)::4]} %B %Y}"

Спробуйте в Інтернеті!


3
%-d- це версія, %dяка не використовується для заміщення, яку ви можете використовувати у форматі рядків замість {g[2]}. Крім того, 12слід стати 12th, а не 12nd(цифри від 10-19 не відповідають тим же правилам, що і 1-9 і 20+)
значення чорнила

1
+1. не знав про fструни
Феліпе Нарді Батіста

@ValueInk дякую! також виправили питання про ординарії
Уріель

5

JavaScript (ES6), 142 140 байт

Виводи NaNth Invalid Dateдля недійсних дат.

Код для порядкових чисел був адаптований з цієї відповіді .

d=>`${s=(D=new Date(d)).getDate()+''}${[,'st','nd','rd'][s.match`1?.$`]||'th'} `+D.toLocaleDateString('en-GB',{month:'long',year:'numeric'})


1
Дає "1 березня 2011 року" за 2011-2-29 у Chrome. Це може бути жорстким виправленням.
Рік Хічкок

5

Python 3.6 , 154 байти

from datetime import*
s=[*map(int,input().split('-'))]
b=s[2]
print(date(*s).strftime(f"%-d{'th'if(3<b<21)+(23<b<31)else('st','nd','rd')[b%10-1]} %B %Y"))

Спробуйте в Інтернеті!(Встановіть вхідний потік, а потім запустіть.)

Завдяки хорошим пропозиціям коментаторів нижче.


Ви можете зберегти байт, видаливши пробіл між int(x)і forу своєму списку.
Крістіан Дін

@ChristianDean Дякую, зробили!
Люк Sawczak

(('st','nd','rd')[b%10-1]if b<4 or 20<b<24 else'th')замість вашого поточного умовного - 3 байти.
Значення чорнила

@ValueInk На жаль, це призведе до 31-го. Інший спосіб, який я думав розбити його, був "th", якщо не 0 <b% 10 <4 або 10 <b <14, але це не зберегло жодних байтів.
Люк Sawczak

У цьому випадку зловживайте типом примусу. (3<b<21)+(23<b<31)за -1 байт. Спробуйте в Інтернеті!
Значення чорнила

5

PHP, 87 байт

<?=checkdate(($a=explode("-",$argn))[1],$a[2],$a[0])?date("jS F Y",strtotime($argn)):E;

Запустити як трубу -Fабо випробувати його в Інтернеті . Завжди друкує чотиризначний рік; провалюється протягом років> 9999.

немає перевірки дійсності, 35 байт:

<?=date("jS F Y",strtotime($argn));

5

Bash + coreutils, 115 78

  • 2 байти збережено завдяки @manatwork.
d="date -d$1 +%-e"
t=`$d`
f=thstndrd
$d"${f:t/10-1?t%10<4?t%10*2:0:0:2} %B %Y"

Спробуйте в Інтернеті .


1
Здається , що з допомогою рядка замість масиву буде трохи допомогти: f=thstndrd; $d"${f:t/10-1?t%10<4?t%10*2:0:0:2} %B %Y".
манатура

1
До речі, ваша версія 1 надихнула підказку Баша . ;)
манатура

@manatwork так - це смішно - я вважав, що намагаюся це зробити, але не думав, що це допоможе. Дякую за натискання
Цифрова травма

4

C #, 147 143 байт

s=>{var t=System.DateTime.Parse(s);int d=t.Day,o=d%10;return d+((d/10)%10==1?"th":o==1?"st":o==2?"nd":o==3?"rd":"th")+t.ToString(" MMMM yyy");}

Збережено 4 байти завдяки @The_Lone_Devil.


Чи не могли б ви не замінити другий t.Dayз dдля економії 4 байта?
The_Lone_Devil

@The_Lone_Devil Звичайно, я міг подякувати, не знаю, як я це пропустив.
TheLethalCoder

4

версія mIRC 7.49 (197 байт)

//tokenize 45 2-2-2 | say $iif($3 isnum 1- $iif($2 = 2,$iif(4 // $1 && 25 \\ $1||16//$1,29,28),$iif($or($2,6) isin 615,30,31))&&$2 isnum1-12&&1//$1,$asctime($ctime($+($1,-,$2,-,$3)date), doo mmmm yyyy))

3

Рубі , 104 103 102 + 8 = 112 111 110 байт

Використовує -rdate -pпрапори програми.

-1 байт від манатурки.

sub(/.*-(\d*)/){Date.parse($&).strftime"%-d#{d=eval$1;(d<4||d>20)&&"..stndrd"[d%10*2,2]||:th} %B %-Y"}

Спробуйте в Інтернеті!


Я пропускаю причину, чому ви не використовували потрійного оператора? d<4||d>20?"..stndrd"[d%10*2,2]:"th"
манатура

@manatwork Число подібних 26спробує отримати доступ до індексів 12..13у рядку пошуку, який знаходиться поза межами, і таким чином повертається nil. Таким чином, використання терміналу робить його d<4||d>20?"..stndrd"[d%10*2,2]||"th":"th", яке довше на 2 байти.
Значення чорнила

А, бачу. Ну, тоді крутий трюк @ValueInk.
манатура

Майже забув, крихітна зміна: "th":th.
манатура

2

C # (.NET Core) , 167 197 байт

s=>s.Equals(DateTime.MinValue)?"":s.Day+((s.Day%10==1&s.Day!=11)?"st":(s.Day%10==2&s.Day!=12)?"nd":(s.Day%10==3&s.Day!=13)?"rd":"th")+" "+s.ToString("MMMM")+" "+s.Year

Спробуйте в Інтернеті!

+30 байт для

using System;

DateTime.Parse()


Ви можете скасувати потрійну перевірку, щоб позбутися від !-1 байта. Ви можете змінити значення &&на &-3 байти. Крім того, оскільки ви використовуєте s.Day7 разів, він економить кілька байт, щоб створити для нього темп-значення:s=>{var t=s.Day;return s.Equals(DateTime.MinValue)?"":t+((t%10==1&t!=11)?"st":(t%10==2&t!=12)?"nd":(t%10==3&t!=13)?"rd":"th")+" "+s.ToString("MMMM")+" "+s.Year;}
Кевін Круїйсен

@KevinCruijssen Дякую!
какарот

Вам також потрібно включити using System;або повністю кваліфікувати DateTimeоб’єкт.
TheLethalCoder

Крім того, DateTime.MinValueце , 1-1-1так що я не думаю , що вам потрібно це перевірити. Що також зробило б моє попереднє зауваження.
TheLethalCoder

1
Якщо приймати дані як DateTimeрозбір та аналіз поза методом, не прийнятно, ви повинні виконати всю роботу всередині методу. Або додайте додатковий метод, щоб розділити роботу.
TheLethalCoder

2

Excel, 212 байт

=ABS(RIGHT(A1,2))&IF(ABS(ABS(RIGHT(A1,2))-12)<2,"th",SWITCH(RIGHT(A1,1),"1","st","2","nd","3","rd","th"))&TEXT(MID(A1,FIND("-",A1)+1,FIND("-",REPLACE(A1,1,FIND("-",A1),""))-1)*30," mmmm ")&LEFT(A1,FIND("-",A1)-1)

Якщо ви розбиваєте його на шматки на кожній амперсанді, ви отримуєте ці шматки:

  • ABS()витягує число дня з двох останніх символів у рядку. Оскільки ця може включати дефіс, ABSперетворює її на позитивну.
  • IF((ABS-12)<2,"th",SWITCH())додає порядковий. -12Біт , тому що 11, 12 і 13 не слід нормальному правилом , і всі вони отримують thзамість st, ndіrd . Це виправляє це.
    • Примітка. Ця SWITCHфункція доступна лише в Excel 2016 та пізніших версіях. ( Джерело ) Це коротше, ніж CHOOSEу цьому випадку, оскільки воно може повернути значення, якщо не знайдено відповідності, тоді як CHOOSEпотрібне числове введення та повинно мати відповідне повернення для кожного можливого значення.
  • TEXT(MID()*30," mmmm ")витягує назву місяця. MID()витягує число місяця у вигляді рядка і множачи на 30 повертає число. Excel розглядає це число як дату (1900-01-30, 1900-02-29, 1900-03-30 тощо) і TEXT()форматує його як ім'я місяця з пробілом на обох кінцях. 28 і 29 також працювали б, але 30 виглядає "приємніше".
  • LEFT() витягує номер року.

Тепер, враховуючи все це, було б набагато простіше, якби всі тестові випадки були у діапазоні дат, який Excel може обробляти як фактичну дату: 1900-01-01 - 9999-12-31. Великою перевагою є те, що вся дата форматується одразу. Це рішення становить 133 байти :

=TEXT(DATEVALUE(A1),"d""" & IF(ABS(ABS(RIGHT(A1,2))-12)<2,"th",SWITCH(RIGHT(A1,1),"1","st","2","nd","3","rd","th")) & """ mmmm yyyy")

Інша велика перешкода повинна була включати порядковий номер. Без цього рішення становить всього 34 байти :

=TEXT(DATEVALUE(A1),"d mmmm yyyy")

1

Швидкий 3: 298 байт

let d=DateFormatter()
d.dateFormat="yyyy-MM-dd"
if let m=d.date(from:"1999-10-3"){let n=NumberFormatter()
n.numberStyle = .ordinal
let s=n.string(from:NSNumber(value:Calendar.current.component(.day, from:m)))
d.dateFormat="MMMM YYY"
print("\(s!) \(d.string(from:m))")}else{print("(error/invalid)")}

Спробуйте в Інтернеті!


8
Ласкаво просимо на сайт! Тут мета полягає в тому, щоб зробити код якомога коротшим, я бачу, у вас довгі імена змінних і багато пробілів, ви можете скоротити і видалити їх, щоб зберегти багато байтів. Також ми зазвичай включаємо заголовок у верхній частині відповіді у формі # Language, N bytes. Було б добре, якби ви могли додати і його.
TheLethalCoder

1

T-SQL, 194 байт

DECLARE @ DATE;SELECT @=PARSE('00'+i AS DATE)FROM t;PRINT DATENAME(d,@)+CASE WHEN DAY(@)IN(1,21,31)THEN'st'WHEN DAY(@)IN(2,22)THEN'nd'WHEN DAY(@)IN(3,23)THEN'rd'ELSE'th'END+FORMAT(@,' MMMM yyy')

Введення здійснюється через текстовий стовпець i в попередньо існуючій таблиці t , в відповідно з нашими стандартами IO .

Працює на дати з 1 січня 0001 по 31 грудня 9999 року. Рік виходить принаймні 3 цифрами (на приклад 150AD).

Недійсні дати призведуть до такої некрасивої помилки:

Error converting string value 'foo' into data type date using culture ''.

Різні параметри мови / культури за замовчуванням можуть змінити цю поведінку. Якщо ви хочете трохи витонченіше вивести помилку (NULL), додайте 4 байти, змінившиPARSE() наTRY_PARSE() .

Формат та пояснення:

DECLARE @ DATE;
SELECT @=PARSE('00'+i AS DATE)FROM t;
PRINT DATENAME(d,@) + 
    CASE WHEN DAY(@) IN (1,21,31) THEN 'st'
         WHEN DAY(@) IN (2,22)    THEN 'nd'
         WHEN DAY(@) IN (3,23)    THEN 'rd'
         ELSE 'th' END
    + FORMAT(@, ' MMMM yyy')

The DATE даних, представлений у SQL 2008, дозволяє набагато ширший діапазон, ніж DATETIMEз 1 січня 0001 по 31 грудня 9999.

Деякі дуже ранні дати можуть бути неправильно розібрані з моїми налаштуваннями місцевості в США ("01-02-03" стає "2 січня 2003"), тому я заздалегідь відклав ще кілька додаткових нулів, щоб було відомо, що перше значення - рік.

Після цього його просто безладний CASEвислів, щоб додати порядковий суфікс до дня. Прикро, команда SQL FORMATне може зробити це автоматично.


1

q / kdb + 210 байт, не конкуруючий

Рішення:

f:{a:"I"$"-"vs x;if[(12<a 1)|31<d:a 2;:0];" "sv(raze($)d,$[d in 1 21 31;`st;d in 2 22;`nd;d in 3 23;`rd;`th];$:[``January`February`March`April`May`June`July`August`September`October`November`December]a 1;($)a 0)};

Приклади:

q)f "2017-08-03"
"3rd August 2017"
q)f "1980-05-12"
"12th May 1980"
q)f "2005-12-3"
"3rd December 2005"
q)f "150-4-21" 
"21st April 150"
q)f "2011-2-29"       / yes it's wrong :(
"29th February 2011"
q)f "1999-10-35"
0

Пояснення:

Це жахливе завдання, оскільки немає форматування дати, тому мені доводиться створювати місяці з нуля (95 байт), а також генерувати суфікс.

Розв’язання, що не перебуває в полі, знаходиться внизу, в основному розділіть вхідний рядок, а потім з'єднайтеся разом після того, як ми додали суфікс і вимкнемо місяць.

f:{
   // split input on "-", cast to integers, save as variable a
   a:"I"$ "-" vs x;
   // if a[1] (month) > 12 or a[2] (day) > 31 return 0; note: save day in variable d for later
   if[(12<a 1) | 31<d:a 2;
     :0];
   // joins the list on " " (like " ".join(...) in python)
   " " sv (
           // the day with suffix
           raze string d,$[d in 1 21 31;`st;d in 2 22;`nd;d in 3 23;`rd;`th];
           // index into a of months, start with 0 as null, to mimic 1-indexing
           string[``January`February`March`April`May`June`July`August`September`October`November`December]a 1;
           // the year cast back to a string (removes any leading zeroes)
           string a 0)
  };

Примітки:

Дати в q повертаються лише до ~ 1709, тому у мене немає тривіального способу підтвердження дати, отже, це неконкурентний запис ... Найкраще, що я можу зробити, це перевірити, чи день> 31 або місяць > 12 і повернути 0.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.