challenge ミリ秒まで含んだ時刻文字列

YYYY年mm月dd日HH時MM分SS.xxx秒なら、「YYYYmmddHHMMSS.xxx」のようにミリ秒まで含んだ文字列を返すプログラムを書いてください。

Posted feedbacks - Nested

Flatten Hidden
WindowsAPIではGetLocalTime()関数を使うとミリ秒単位の時刻が取得できます。
ただし、クロックの分解能(精度)は15~16ミリ秒ほどのようです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <stdio.h>
#include <windows.h>

int main(int argc, char **argv)
{
    SYSTEMTIME    st;
    GetLocalTime(&st);
    printf("%04d%02d%02d%02d%02d%02d.%03d\n",
        st.wYear, st.wMonth,  st.wDay,
        st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
    return 0;
}

>クロックの分解能(精度)は15~16ミリ秒ほどのようです。 タスクスイッチが15mSec前後で発生しておりGetSystemTime/GetLocalTimeまたGetTickCountもそのとき保持した時刻を更新することなく返すからそう見えるわけですね。 ループにして複数実行してみれば分解能15~16ミリ秒ほどと思えたところが保証されなくなることも見えるのでしょう。出題はミリ秒を得る方法を得たいのであってそれ以上のことは求めていないのでしょうけど。

var t = new Date();
print(DatetoString(t))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function DatetoString(t){
    return (""
        + paddingLeft(t.getFullYear(), 4, '0')
        + paddingLeft(t.getMonth()+1, 2, '0')
        + paddingLeft(t.getDate(), 2, '0')
        + paddingLeft(t.getHours(), 2, '0')
        + paddingLeft(t.getMinutes(), 2, '0')
        + paddingLeft(t.getSeconds(), 2, '0')
        + "."
        + paddingLeft(t.getMilliseconds(), 3, '0')
    );
}

if(!String.prototype.x){
    String.prototype.x = function(n){
        var result="", i;
        for(i=0;i<n;i++){
            result += this;
        }
        return result;
    }
}
function paddingLeft(str, d, c){
    var len  = str.toString().length;
    var x = d > len ? d - len : 0;
    
    return c.x(x) + str;
}

現在日時を表示してみました。

1
2
3
4
import java.text.*

def now = new Date()
println new SimpleDateFormat("yyyyMMddhhmmss.SSS").format(now)
ミリ秒未満は切り捨て
実行例

*Main> :main
20080615084301.575
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
module Main where

import Data.Time
import System.Locale

($$) = flip ($)
main = getCurrentTimeZone >>= \ tz ->
       getCurrentTime     >>= \ ct ->
       utcToLocalTime tz ct $$ formatTime defaultTimeLocale "%Y%m%d%H%M%S.%q"
                            $$ take 18
                            $$ putStrLn

Squeak Smalltalk で。

#format: の引数のルールは次のようになっています。sep に 0 を渡すとセパレータなしにできるようです。

--

#(item item item sep monthFmt yearFmt twoDigits)

items: 1=day 2=month 3=year will appear in the order given, separated by sep which is eaither an ascii code or character.

monthFmt: 1=09 2=Sep 3=September

yearFmt: 1=1996 2=96

twoDigits: (missing or)1=9 2=09.

1
2
3
4
5
| yyyymmdd hhmmss xxx |
yyyymmdd := Date today printFormat: #(3 2 1 0 1 1 2).
hhmmss := Time now print24 copyWithout: $:.
xxx := Time millisecondClockValue printString last: 3.
^yyyymmdd, hhmmss, '.', xxx

× #format: の引数のルールは

○ #printFormat: の引数のルールは

SimpleDateFormatは #6498 で使われていたので、 String$format を使ってみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import java.util.Date;

public class Sample184 {
    public static String convert(Date date) {
        return String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS.%1$tL", date);
    }

    public static void main(String[] args) {
        System.out.println(convert(new Date()));
    }
}
1
puts Time.now.instance_eval{'%s.%03d'%[strftime('%Y%m%d%H%M%S'),(usec/1000.0).round]}
あ、.roundしちゃだめだった。xx秒999500でxx秒1000とかなるよね
すみません、寝むくてぐだぐだな感じで。
1
2
3
> {{Y,M,D},{Ho,Mi,Se}}=calendar:now_to_local_time({Mg,S,Ms}=now()).
> element(2,regexp:gsub(lists:flatten(io_lib:format("~4w~2w~2w~2w~2w~2w.~w",[Y,M,D,Ho,Mi,Se,Ms]))," ","0")). 
"20080615141401.573000"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <sys/time.h>
#include <stdio.h>
int
main(void)
{
    struct timeval t;
    time_t c;
    struct tm r;

    gettimeofday(&t, NULL);
    c = t.tv_sec;
    localtime_r(&c, &r);
    printf("%04d%02d%02d%02d%02d%02d.%03d\n", r.tm_year + 1900, r.tm_mon + 1, r.tm_mday, r.tm_hour, r.tm_min, r.tm_sec, (int)(t.tv_usec / 1000));
    return 0;
}
1
2
3
import datetime
now = datetime.datetime.now()
print now.strftime("%Y%m%d%H%M%S.") + "%03d" % (now.microsecond // 1000)
D 1.0 + Tangoです。
文字列を「返す」プログラムという問題なので、現在日時から文字列を作る処理だけ別関数に切り出しています。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import tango.io.Console;
import tango.text.convert.Layout;
import tango.time.WallClock;

char[]
datetime_string()
{
    auto layout = new Layout!(char);
    auto datetime = WallClock.toDate;    // 現在の日時 (ローカルタイム)
    auto d = datetime.date;
    auto t = datetime.time;
    return layout.convert("{:d4}{:d2}{:d2}{:d2}{:d2}{:d2}.{:d3}",
        d.year, d.month, d.day,
        t.hours, t.minutes, t.seconds, t.millis);
}

void
main()
{
    Cout(datetime_string).newline;
}

Boost使ってみました。 ちゃんと理解していないので、出力のあたりがちょっと汚らしい。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <cstdlib>
#include <iostream>
#include <boost/format.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

using namespace std;
using namespace boost;
using namespace boost::gregorian;
using namespace boost::posix_time;

int main(void)
{
        ptime now = microsec_clock::local_time();

        cout    << format("%s%02d%02d%02d.%03d")
                % to_iso_string(now.date()).c_str()
                % now.time_of_day().hours()
                % now.time_of_day().minutes()
                % now.time_of_day().seconds()
                % (now.time_of_day().fractional_seconds() / 1000)
                << endl;

        return EXIT_SUCCESS;
}
1
2
3
4
5
6
7
8
using System;

class Program {
    static void Main(string[] args) {
        Console.WriteLine(DateTime.Now.ToString("yyyyMMddHHmmss.fff"));
        Console.ReadLine();
    }
}

ついでにQtで書いてみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <QtCore>

#include <cstdlib>
#include <iostream>

using namespace std;

int main(void)
{
        QDateTime now = QDateTime::currentDateTime();

        cout << now.toString("yyyyMMddhhmmss.zzz").toStdString() << endl;

        return EXIT_SUCCESS;
}
CPANモジュールのTime::Formatを使って。
1
2
use Time::Format qw(%time);
print "$time{'yyyymmddhhmmss.mmm'}\n";

PostScript では realtime オペレータで現在時刻を取り出せるのですが、なんと原点(0)がいつを指すかは未定義です。 そのため、別途パラメータで補ってやる必要があります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
%!PS

/ZeroNum { % integer (string) ZeroNum (string')
    dup dup length dup string
    5 -1 roll exch cvs dup length
    3 -1 roll sub neg exch putinterval
} bind def

/GetClock { %
    % Input
    %   Offset1(YYYYMMDD in int)
    %   Offset2(offset for realtime clock to 00:00:00.000 in millisec)
    % Output
    %    (String)
    (YYYYMMDD000000.000) dup 0 8 getinterval 4 -1 roll exch ZeroNum pop
    exch
    realtime 86400000 mod add 86400000 add 86400000 mod
    dup 1000 mod  2 index 15 3 getinterval ZeroNum pop 1000 idiv 
    dup 60 mod 2 index 12 2 getinterval ZeroNum pop 60 idiv
    dup 60 mod 2 index 10 2 getinterval ZeroNum pop 60 idiv
    1 index 8 2 getinterval ZeroNum pop
} bind def

% ========= Test Code ============
20080616 32940000 GetClock ==
> options(digits.secs=3)
> Sys.time()
[1] "2008-06-17 01:55:32.562 東京 (標準時)"
1
2
options(digits.secs=3)
Sys.time()

シンプルにしようと思ったんだが、あんまりシンプルにならなかった。

1
2
3
4
date_default_timezone_set('Asia/Tokyo');
$time=split(' ',microtime
());
print(date('YmdHis').'.'.substr($time[0],2,3));

変な改行が入ってしまった・・・。 microtime と ()); の間の改行は不要です。

標準モジュール(Perl v5.8.7) Time::HiResを使って書いてみました。

1
2
3
4
5
use Time::HiRes;
my ($wtime,$msec) = split(/\./ , Time::HiRes::time);
my @t = localtime($wtime);
printf("%04d%02d%02d%02d%02d%02d.%03d",
       $t[5]+1900,$t[4]+1,$t[3],$t[2],$t[1],$t[0],($msec/100));

ActivePerl v5.10.0 build 1003ではsubstr($msec . '0' x 3, 0, 3)みたい。実装が違うということかな?

Gauche (Scheme) で SRFI-19 を使って書いてみました。
1
2
3
4
5
6
(use srfi-19)
(define get-date-string (lambda ()
    (let ((date (current-date)))
        (string-append
            (date->string date "~Y~m~d~H~M~S") "."
            (format #f "~3,'0d" (quotient (date-nanosecond date) (expt 10 6)))))))

現在時刻を表示できる関数から 年月日時分秒をリストにして取り出しました。

1
2
(defun todaydate () 
(princ (cdr (cdr (cdr(reverse (multiple-value-list (get-decoded-time))))))))

間違えましたCommonLispです

1
2
(defun todaydate () 
(princ (cdr (cdr (cdr(reverse (multiple-value-list (get-decoded-time))))))))
「6!:0」は現在の日付・時刻のリストを返す。

   6!:0
2008 6 23 15 55 21.345

   dateString ''
20080623155521.345

データは揃っているので、printfを使えばできあがりと思ったら、
フォーマットの指定が、c言語なんかとは、だいぶ違うようで結局、
データを加工することになってしまいました。
1
2
3
4
5
load 'printf'
dateString=:3 :0
a =. 6!:0 ''
'%.4d%.2d%.2d%.2d%.2d%.2d.%.3d' printf a,1e3*1|{:a
)
J602 から日時を取得する動詞に書式指定ができるようになっていた。
1
dateString =: (6 !: 0) & 'YYYYMMDDhhmmss.sss'
HSP 3.2 では strf で複数引数に対応します。
3.0、3.1では面倒ですが一つ一つ strf 関数を使った結果を連結していきます。
1
2
3
4
; 3.0, 3.1
mes strf("%04d",gettime(0))+strf("%02d",gettime(1))+strf("%02d",gettime(3))+strf("%02d",gettime(4))+strf("%02d",gettime(5))+strf("%02d",gettime(6))+"."+strf("%03d",gettime(7))
; 3.2
mes strf("%04d%02d%02d%02d%02d%02d.%03d", gettime(0), gettime(1), gettime(3), gettime(4), gettime(5), gettime(6), gettime(7))
WinAPIのGetLocalTimeを使っています。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
●GetLocalTime({参照渡}LPSYSTEMTIME) =DLL("kernel32.dll","VOID GetLocalTime(LPSYSTEMTIME)")
●詳細時刻取得
    SYSTEMTIMEとは文字列
    Iとは整数
    BUFとは配列
    SYSTEMTIMEに16を確保 //16bit*8[byte]
    GetLocalTime(SYSTEMTIME)
    Iで0から7まで繰り返す
        BUF[I]=SYSTEMTIMEの(I*2+1)を"WORD"でバイナリ取得
    BUFで戻る

●時刻整形(T)
    BUFとは文字列
    Iとは整数
    T[0]=T[0]を4でゼロ埋め //年
    T[7]=T[7]を3でゼロ埋め //ミリ秒
    Iで1から6まで繰り返す
        T[I]=T[I]を2でゼロ埋め
    T[0]&T[1]&T[3]&T[4]&T[5]&T[6]&"."&T[7]で戻る
    #"{T[0]}年{T[1]}月{T[3]}日{T[4]}時{T[5]}分{T[6]}.{T[7]}秒"で戻る

テストエディタとはエディタ
その幅は200
1の間
    テストエディタ=時刻整形(詳細時刻取得)
    0秒待つ

Tcl8.5の場合は、 clock millisecondsが使える。 clock microsecondsも使える。

Tcl8.4の場合は、 最近のActiveTclにバックポートとして入っているnewclock拡張を使う。

1
2
3
4
set pit [clock milliseconds]
set sec [clock format [string range $pit 0 9] -format %Y%m%d%H%M%S]]
set msec [string range $pit 10 end]
puts $sec.$msec
CLでは、秒より細かい単位で時間を取得できますが、
その粒度は処理系依存のようです。
SBCLとCLISPに対応してみました。

(get-universal-time+millisecond-string)
;==> "20080711160627.511"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
(defconstant +unix-time-origin+ (encode-universal-time 0 0 0 1 1 1970 0))

(defun get-universal-time+millisecond-string ()
  (multiple-value-bind (time ms)
      #+sbcl (sb-unix::system-real-time-values)
      #+clisp (floor (get-internal-real-time) internal-time-units-per-second)
      (multiple-value-bind (s m h d mo y)
          (decode-universal-time (+ +unix-time-origin+ time))
        (format nil "~D~2,'0D~2,'0D~2,'0D~2,'0D~2,'0D.~A" 
                y mo d h m s (truncated-millisecond-string ms)))))

(defmacro truncated-millisecond-string (n)
  (let* ((fig (1- (length 
                   (princ-to-string internal-time-units-per-second))))
         (form `(format nil ,(format nil "~~~D,'0D" fig) ,n)))
    (if (= 3 fig)
        form
        `(subseq ,form 0 3))))

ほとんどJavaですが...。

1
2
3
4
5
6
7
8
import    java.util.Date
import    java.text.SimpleDateFormat

object Millisecond {
    def main(args:Array[String]):Unit = {
        Console.println(new SimpleDateFormat("yyyyMMDDHHmmss.S").format(new Date))
    }
}

”DD”は”dd”でないと表示がおかしくなりませんか?

識別子は大文字、小文字の区別はないのでした。
print はウィンドウを開きそこに表示します。またログファイルにも記録します。
メインプログラムは、関数、サブルーチンの定義の直前までです。
最初、関数定義の後ろに書いていて何故、実行できないのだろうと悩んでいました。
1
2
3
4
5
6
print date_string() //=>20080903143211.840

FUNCTION date_string()
  GETTIME()
  RESULT = G_TIME_YY4 + G_TIME_MM2 + G_TIME_DD2 + G_TIME_HH2 + G_TIME_NN2 + G_TIME_SS2 + "." + G_TIME_ZZ2
FEND
バッチで。

10ミリ秒単位までしか表現できないので、末尾に 0を補っています。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@echo off
setlocal
  set d=
  set t=
  
  chcp 932 > NUL
  
  for /f %%d in ('date /t') do set d=%%d
  
  for /f "tokens=2" %%t in ('echo. ^| time') do set t=%%t
  
  echo %d:/=%%t::=%0
endlocal

SQL Server 2008 で確認しました。

1
SELECT GETDATE()

Index

Feed

Other

Link

Pathtraq

loading...