Um ano fracionário

8

Meu feriado de PPCG acabou: D

Introdução

O tempo fracionário é the year + (the value (minute of year) / number of minutes in the year).

Exemplo de cálculo

Você deve assumir que fevereiro sempre tem 28 dias e o ano sempre tem 365 dias.

Digamos que queremos converter o tempo: 17:34 3rd March 2013em tempo fracionário. Em primeiro lugar, você encontra quantos minutos houve em 2013: 525600 minutos . Vamos chamar assim x.

Em seguida, você deseja descobrir quantos minutos existem desde o início de 2013. Alguns cálculos rápidos indicam que a resposta é 88894 minutos:

Houve 61 dias desde o início do ano, que vezes 1440 (número de minutos em um dia) é igual a 87840 minutos. Em 17 horas são 1020 minutos (17 * 60). Agora, podemos adicionar 87840, 1020 e 34 minutos para equivaler a 88894 minutos.

Vamos chamar assim y.

Finalmente, você dividir ypor xe adicione o ano, resultando em 2013.16912(a 5 casas decimais).

Entrada

A data e a hora serão fornecidas como uma única sequência. A sequência estará no seguinte formato:

YYYY-MM-DD hh:mm 

O horário sempre estará no formato de 24 horas e o ano sempre estará no intervalo de 1900-2050, inclusive.

Exemplos

Input:  2016-08-06 23:48
Output: 2016.59723

Input:  2013-03-03 17:34
Output: 2013.16912

Input:  1914-11-11 11:11
Output: 1914.86155

Se você está indo para a recompensa, faça ping nos comentários ou no The XIX XIX Byte .

Desafio

Calcule a data e hora especificadas como um ano fracionário.

Forneça toda a saída com cinco casas decimais (você pode arredondar da maneira que desejar: piso, teto ou arredondamento verdadeiro). O menor código vence.

Recompensa

Estou oferecendo uma recompensa de 100 repetições para o programa mais curto, que também aceita a data no formato de ano fracionário e retorna a hora no YYYY-MM-DD hh:mmformato. Em essência, seu programa (ou função) deve agir da seguinte maneira:

f('1914-11-11 11:11') => 1914.86155
f('1914.86155')       => 1914-11-11 11:11
  1. t-clausen.dk - 154 bytes
  2. Neil - 183 bytes

Entre os melhores

Beta Decay
fonte
Talvez tomar a data e a hora como uma entrada permitiria casos de teste e verificação mais fácil?
Luis Mendo
Estou um pouco confuso sobre se este leva em conta anos bissextos dada For this, assume February has 28 days and the year is 365 days long., mas também... using the Gregorian calendar.
Destrutível Lemon
@DestructibleWatermelon Não, ele não leva em consideração os anos bissextos
Beta Decay
podemos dar mais de cinco casas decimais?
Destructible Lemon
@DestructibleWatermelon No
Beta Decay

Respostas:

1

TSQL, 63 bytes

Esta é uma versão mais curta que a minha resposta original, porque minha primeira resposta incluiu cálculo para o ano bissexto.

DECLARE @ DATETIME ='2016-08-06 23:48'

PRINT LEFT(YEAR(@)+DATEDIFF(mi,0,STUFF(@,1,4,1900))/525600.,10)

Violino

O sql a seguir pode manipular os dois tipos de entrada

TSQL, 154 bytes

DECLARE @ VARCHAR(16) ='1914-11-11 11:11'--can be replaced with '1914.86155'

PRINT IIF(isdate(@)=1,LEFT(YEAR(@)+DATEDIFF(mi,0,STUFF(@,1,4,1900))/525600.,10),LEFT(@,4)+RIGHT(CONVERT(CHAR(16),DATEADD(mi,1*RIGHT(@,5)*5.256,0),20),12))

Fiddle combinado 1

Violino combinado 2

t-clausen.dk
fonte
5

JavaScript (ES6), 84 bytes

f=
s=>(Date.parse(1970+s.slice(4).replace(/ /,'T')+'Z')/31536e6+parseInt(s)).toFixed(5)
;
<input placeholder=Input oninput=o.value=f(this.value)><input placeholder=Output id=o>

Supondo que não sejam necessários anos bissextos ou horário de verão, substituo o ano por 1970, que Date.parseretorna diretamente o deslocamento de tempo em milissegundos, dos quais houve 31536000000em 1970 (ou qualquer outro ano sem bissexto). Tudo o que preciso fazer é adicionar novamente o ano e arredondar para 5 casas decimais. Editar: conversão bidirecional em 183 178 bytes:

f=
s=>/:/.test(s,m=31536e6)?(Date.parse(1970+s.slice(4).replace(/ /,'T')+'Z')/m+parseInt(s)).toFixed(5):s.slice(0,4)+new Date(s.slice(4)*m+3e4).toJSON().slice(4,16).replace(/T/,' ')
;
<input placeholder=Input oninput=o.value=f(this.value)><input placeholder=Output id=o>

Supõe que as seqüências contendo um :formato de hora são, tratadas como acima, retira o ano, converte em milissegundos, adiciona meio minuto para fins de arredondamento, converte para uma data em 1970, extrai o mês, dia, hora e minuto e prefixa o ano original.

Neil
fonte
@ βετѧΛєҫαγ Sim, sé o argumento para a função.
Neil
Isso não gera resultados inválidos, porque o desafio solicita explicitamente que fevereiro tenha apenas 28 dias e 365 dias por ano no total?
AdmBorkBork 08/08
@ TimmyD às vezes fevereiro tem 29 dias. Vamos supor que não significa que ele é dissallowed aos anos bissextos alça corretamente
t-clausen.dk
@ t-clausen.dk Desculpe, eu quis dizer que os anos bissextos não devem ser tratados #
Decay Beta
@ βετѧΛєҫαγ Agora, usando nem os anos bissextos nem o horário de verão, também possui uma versão reversível. Isso é satisfatório?
Neil
2

Matlab, 132 115 bytes

 d=input('');m=cumsum([-1 '# #"#"##"#"'-4]);year(d)+fix((((m(month(d))+day(d))*24+hour(d))*60+minute(d))/5.256)/10^5

Arredonda para 0.

Hmmm ... isso é muito longo.
Isso está usando alguns componentes internos, mas não os realmente úteis - por causa dos anos bissextos.

A análise direta da string fornece mais 2 bytes de solução:

d=sscanf(input(''),'%d%[- :]');m=cumsum([-1 '# #"#"##"#"'-4]);d(1)+fix((((m(d(3))+d(5))*24+d(7))*60+d(9))/5.256)/10^5

As versões mais recentes do Matlab provavelmente têm uma função de divisão melhor, mas estou executando em 2012a.

Alguns bytes salvos graças ao @Luis Mendo

pajonk
fonte
Você pode definir a matriz com [-1 '# #"#"##"#"'-4]para salvar alguns bytes. São yearetc funções padrão? Se você estiver usando uma caixa de ferramentas, indique-a no título, por exemplo "Matlab with Financial Toolbox"
Luis Mendo
@LuisMendo Não estou familiarizado com a #anotação e nunca a encontrei. Onde posso ler mais sobre isso (a pesquisa rápida no Google não ajudou)? Eu acho que os yearetc. são funções padrão, mas não sei se eles se comportam da mesma maneira fora da caixa de ferramentas (documentos) .
Pajonk
Não é uma notação especial. É apenas uma string com caracteres que possuem os códigos ASCII apropriados para produzir os números necessários. Quanto às funções, eu não sabia, obrigado por esclarecer. O Matlab 15b parece não tê-los
Luis Mendo
Oh, isso é inteligente.
Pajonk
1

PowerShell v3 +, 131 bytes

$t=date $args[0];$a=1440*!!(date "2-29-$($t.year)");"{0:F5}"-f((($t.DayOfYear-1)*1440+$t.TimeOfDay.TotalMinutes-$a)/525600+$t.Year)

Pega entrada $args[0]e converte-a Get-Datepara armazenar em [datetime]formato .NET , armazena em $t. Calcula se existe 29 de fevereiro e define, $apara subtrairmos o valor de minutos dessa data (se houver).

Em seguida, usamos o -foperador ormat com uma especificação de cadeia fixa de 5 dígitos decimais para executar o cálculo. Usos built-ins para calcular a .DayOfYearea .TotalMinutesda entrada dada, subtrair $ase é um ano bissexto, divida por 525600minutos no total, e adicionar a entrada .Year.

Irá reclamar (verbalmente) ao STDERR se 29 de fevereiro não existir (veja os exemplos abaixo), mas como o STDERR é ignorado por padrão, não nos preocupamos com isso. Além disso, observe que o PowerShell faz o arredondamento do banqueiro por padrão.

Exemplos

PS C:\Tools\Scripts\golfing> .\fractional-year.ps1 '2016-08-06 23:48'
2016.59724

PS C:\Tools\Scripts\golfing> .\fractional-year.ps1 '2013-03-03 17:34'
Get-Date : Cannot bind parameter 'Date'. Cannot convert value "2-29-2013" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."
At C:\Tools\Scripts\golfing\fractional-year.ps1:7 char:36
+   $t=date $args[0];$a=1440*!!(date "2-29-$($t.year)");"{0:F5}"-f((($t.DayOfYear- ...
+                                    ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-Date], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.GetDateCommand

2013.16913

PS C:\Tools\Scripts\golfing> .\fractional-year.ps1 '1914-11-11 11:11'
Get-Date : Cannot bind parameter 'Date'. Cannot convert value "2-29-1914" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."
At C:\Tools\Scripts\golfing\fractional-year.ps1:7 char:36
+   $t=date $args[0];$a=1440*!!(date "2-29-$($t.year)");"{0:F5}"-f((($t.DayOfYear- ...
+                                    ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-Date], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.GetDateCommand

1914.86155

Como alternativa, com anos bissextos, 119 bytes

"{0:F5}"-f((($t=date $args[0]).DayOfYear-1+$t.TimeOfDay.TotalMinutes/1440)/(date "12-31-$($t.year)").DayOfYear+$t.Year)

Se seguirmos as configurações da agenda, podemos cortar uma dúzia de bytes, porque não precisaremos levar em consideração $ao código original acima. Isso nos permite passar $tpara a própria expressão, e calcularemos explicitamente o valor .DayOfYearpara 31 de dezembro. Caso contrário, segue a mesma metodologia.

AdmBorkBork
fonte
0

Python 3, 163 173 bytes

mais bytes por causa do formato de saída

não usa data incorporada, como a resposta em java.

def s(x):z=x[5:10].split("-");v=x[10:].split(":");return int(x[:4])+(sum(([-1,31,28]+[31,30,31,30,31]*2)[:int(z[0])],int(z[1]))*1440+int(v[0])*60+int(v[1]))/525600

um pouco mais legível

def s(x):
    date=x[5:10].split("-");time=x[10:].split(":")
    return int(x[:4])+(sum(([-1,31,28]+[31,30,31,30,31]*2)[:int(date[0])],int(date[1]))*1440+int(time[0])*60+int(time[1]))/525600
Limão destrutível
fonte
0

Perl 6 ,  107 105  102 bytes

{$/=.comb(/\d+/);($0+(sum(|flat(-1,31,28,(31,30,31,30,31)xx 2)[^$1],$2)*1440+$3*60+$4)/525600).fmt: '%.5f'}
{$/=.comb(/\d+/);fmt $0+(sum(|flat(-1,31,28,(31,30,31,30,31)xx 2)[^$1],$2)*1440+$3*60+$4)/525600: '%.5f'}

{$/=.comb(/\d+/);fmt $0+(flat($2-1,31,28,(31,30,31,30,31)xx 2)[^$1].sum*1440+$3*60+$4)/525600: '%.5f'}
{$/=.comb(/\d+/);round $0+(flat($2-1,31,28,(31,30,31,30,31)xx 2)[^$1].sum*1440+$3*60+$4)/525600,.1⁵}

Explicação:

{
  $/ = .comb(/\d+/); # grab a list of only the digits
  # 「$0」 is short for 「$/[0]」

  fmt

    $0 # year
    +
    (
      flat(
        $2 -1,                     #    days
        31,28,(31,30,31,30,31)xx 2 # -+ months
      )[^$1].sum * 1440            # /
      + $3 * 60                    #    hours
      + $4                         #    minutes
    )
    /
    525600

  : '%.5f' # the 「:」 is used here as 「fmt」 is a method not a subroutine
}

Teste:

#! /usr/bin/env perl6
use v6.c;
use Test;

# returns Str
my &fractional-year-a = {$/=.comb(/\d+/);fmt $0+(sum(flat($2-1,31,28,(31,30,31,30,31)xx 2)[^$1])*1440+$3*60+$4)/525600: '%.5f'}
# returns Rat
my &fractional-year-b = {$/=.comb(/\d+/);round $0+(sum(flat($2-1,31,28,(31,30,31,30,31)xx 2)[^$1])*1440+$3*60+$4)/525600,.1⁵}

my @tests = (
  '2016-08-06 23:48' => 2016.59723,
  '2013-03-03 17:34' => 2013.16912,
  '1914-11-11 11:11' => 1914.86155,
);

plan +@tests * 2;

for @tests -> $_ ( :key($input), :value($expected) ) {
  is-approx +fractional-year-a($input), +$expected, 1e-5, "a $input => $expected";
  is-approx +fractional-year-b($input), +$expected, 1e-5, "b $input => $expected";
}
1..6
ok 1 - a 2016-08-06 23:48 => 2016.59723
ok 2 - b 2016-08-06 23:48 => 2016.59723
ok 3 - a 2013-03-03 17:34 => 2013.16912
ok 4 - b 2013-03-03 17:34 => 2013.16912
ok 5 - a 1914-11-11 11:11 => 1914.86155
ok 6 - b 1914-11-11 11:11 => 1914.86155
Brad Gilbert b2gills
fonte