質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.40%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

3回答

15002閲覧

C# 24時間以上の時間(シリアル値)をhh:mmの形で取得したい

tc_hiro

総合スコア17

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2020/10/26 05:13

編集2020/10/26 05:44

Excelの勤怠データを、C#で取り込みたいです。

取り込みたいのは、
[h]:mm の形式で表示している合計勤務時間のセルです。
月の合計勤務時間なので、24時間を上回ります。

表示されているそのままの形で取り込みたいのですが、
Cells("A1").Text で取り込むと、表示されている値とは異なる値が取得されます。(下記例)

(例)
Excel「0:00」→C#「12:12」
Excel「130:00」→C#「10.01」

C#

1DateTime.FromOADate(Convert.ToDouble(Cells("A1").Value))

でDateTime型に取り込んでから何とか処理できないかと考えましたが
うまくいきません。

何か良い方法があればご教示いただけば幸いです。


補足です。
情報不足、失礼いたしました。

DateTime 型として正しい値は取れています。

Excel 表記「188:30」 シリアル値「7.85416666666666」
C# DateTime「1900/01/06 20:30:00」

ここから、「188:30」との表記へ変換する方法が分かりません。
ご教示のほどよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/10/26 05:20

DateTime.FromOADate メソッドで正しく .NET の DateTime 型のオブジェクトを取得できないのか、DateTime 型として正しい値は取れているがそれを望む形に書式設定ができないのか、どちらですか?
退会済みユーザー

退会済みユーザー

2020/10/26 05:36

どういう計算で DateTime「1900/01/06 20:30:00」が 「130:00」になるのでしょう? Microsoft のドキュメントによると "OLE オートメーション日付は、浮動小数点数として実装され、1899 年 12 月 30 日の深夜からの日数を示します" とのことですが、1899 年 12 月 30 日の深夜から数える?
tc_hiro

2020/10/26 05:44

大変失礼いたしました。「130:00」ではなく「188:30」です。修正いたしました。
Zuishin

2020/10/26 07:02 編集

var t = 7.85416666666666 * 24; // 188.5; Console.WriteLine($"{Math.Floor(t)}:{Math.Floor((t - Math.Floor(t)) * 60):00}");
guest

回答3

0

そもそもDateTime構造体ある日時の瞬間を示すデータなので期間を格納は間違っています。
期間を格納するのであれば、TimeSpan構造体を使ってください。

また、TimeSpan.ParseExactは24時間を超えるもの(例えば"30:00")を変換することが出来ません。
なので、":"で分割してコンストラクタで指定するような形になります。

C#

1TimeSpan t = new TimeSpan(130,0,0);

追記

シリアル値であれば、そのシリアル値に24を掛ければ、188.5と整数部が時間、小数部が分と取得できるかと思います。

投稿2020/10/26 05:33

編集2020/10/26 06:06
YAmaGNZ

総合スコア10383

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tc_hiro

2020/10/26 05:42

回答ありがとうございます。 おっしゃる通り、DateTime型に格納するのが間違っているのは把握しているのですが、 シリアル値を時間に変換する方法が他に分からず、 DateTime型からTimeSpanなど何か使って「130:00」を導き出せないかと思考錯誤の途中です。 シリアル値から直接「130:00」を導き出せるのであれば、 DateTimeを使用する必要は無いと考えています。
tc_hiro

2020/10/26 06:35

ありがとうございます。 シリアル値を整数部と小数部に分けて24をかけるところまでは辿り着きそこで詰まっていたのですが 確かに、そもそもシリアル値に24をかければ良かったですね。 早速試してみました。 ```C# double time_db = Convert.ToDouble(7.85416666666666); int hour = (int)(time_db * 24); DateTime dt = DateTime.FromOADate(time_db % 1); string ret = hour + ":" + dt.ToString("mm"); ``` こちらで一見成功したように思えたのですが、 シリアル値「0.291666」の場合、24を掛けた結果が「6.999」で時間が6となってしまいました。 しかしかなり正解に近づけたように思います。 ありがとうございます。
YAmaGNZ

2020/10/26 06:58

シリアル値「0.291666」の場合とはどのような値でしょうか? エクセルに「7:00」と入れた場合、0.291666666666667となり、計算結果は7となります。
YAmaGNZ

2020/10/26 07:31

シリアル値「0.291666」の場合はどの方法を使っても6時間としか取れないのでは? エクセルで書式の最小単位が秒までの場合、丸められて"7:00:00"と表示されてしまいますが、ミリ秒まで表示すれば”6:59:59.942”と正しい値が表示されます。 FromOADateを使った場合(DateTime.FromOADate(0.291666) - DateTime.FromOADate(0))も正確な値の6:59:59.942となり6時間となります。
tc_hiro

2020/10/27 00:19

確認が遅くなり申し訳ありません。 言葉が足りませんでしたが、7時間が正しい値(Excel上で「7:00」)で、 それを取得した時のシリアル値が「0.291666」なので上記の記載となりました、失礼いたしました。 丸めが必要な場合以外は正しく取得できたのですが、このような場合は難しそうですね。 幸い、SurferOnWww様にご回答いただいたTimeSpanを用いた場合ですと 7時間で取得できましたので、今回はそちらの方法を使用させていただくことにいたしました。 ご検討くださりありがとうございました。
YAmaGNZ

2020/10/27 01:09 編集

すみません。お聞きしたいことがあります。 SurferOnWwwさんのコード+コメント欄で書かれていたコードの DateTime date = DateTime.FromOADate(0.291666); DateTime start = new DateTime(1899,12,30,0,0,0); TimeSpan span = date - start; int d = (int)(span.TotalHours); string h = span.ToString("mm"); string ret = d + ":" + h; をシリアル値0.291666にて実行しましたが結果は「6:59」となります。 どのようなコードで実行したら7時間となるのでしょうか?
tc_hiro

2020/10/27 05:01

コードはご記載の通りで間違いありません。 7時間のシリアル値が正確には「0.29166666666666663」で、 そちらで実行すると「7:00」を取得できます。 最初から正確な数値を記載すべきでした、申し訳ございません。
guest

0

ベストアンサー

C# DateTime「1900/01/06 20:30:00」
ここから、「188:30」との表記へ変換する方法が分かりません。

OLE オートメーション日付の基準 1899 年 12 月 30 日の深夜からの「時間:分」を取得したいと理解してレスします。

以下のようにすれば TimeSpan として取得できます。

イメージ説明

だたし、普通に書式指定したのでは 24 時間を超える部分は「日」となって上の画像のように 7.20:30:00 という形になってしまいます。

それが NG なら、書式設定の方法は以下の記事のようにいろいろありますので、望む形に近いものを探してみてはいかがですか。

カスタム TimeSpan 書式指定文字列
https://docs.microsoft.com/ja-jp/dotnet/standard/base-types/custom-timespan-format-strings

それも NG なら、Ticks プロパティでタイマ刻み(100 ナノ秒単位)の数(上の画像で tick)を取得して計算するぐらいしか手はなさそうです。

投稿2020/10/26 06:18

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tc_hiro

2020/10/26 06:57

ご回答ありがとうございます。 ご教示いただいたコードに続けて下記コードを追記し、得たい文字列を取得できました! int d = (int)(span.TotalHours); string h = span.ToString("mm"); string ret = d + ":" + h; TimeSpanに入れての実装はちらついたものの分からなかったので、 とても勉強になりました。 本当にありがとうございました。
guest

0

とりあえず方針だけ

シリアル値をDateTime型として受け取ることができてるなら、そのDateTime型を文字列に変換し、文字列の中から必要な数値(時分秒)を個別に抽出して整数値にする→60進数(時刻表現)の各数値が得られるので、自分が10進数表記に変換したい桁に併せて計算する(mを10進数にしたいなら1h=60mとしてmに足す)→表示したいお好きなフォーマットで文字列に変換する。

でできます。

投稿2020/10/26 05:26

編集2020/10/26 06:04
gentaro

総合スコア8949

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tc_hiro

2020/10/26 05:31

ご回答ありがとうございます。 私の質問内容が不明確で失礼いたしました。 結果として取得したいのが「130:00」で、 現状はシリアル値、もしくはDateTime型での値しか取得できていない状態です。
gentaro

2020/10/26 05:47

あぁ、そういうことですか。 ところでEXCELのセルの書式設定はどうなってるんですか? EXCELでもちゃんと「時刻」と設定されているものじゃないとそのまま変換できないのは当然なんですが、おそらくEXCELで時刻表示を「130:00」と出すのは無理ですよね? ただの文字列になっているのならTextで参照すればそのままいけそうなもんですが。
tc_hiro

2020/10/26 05:52

Excel上では [h]:mm の書式に設定しており、「130:00」と表示ができております。
gentaro

2020/10/26 05:56

変わっとるやんけ > Excel 表記「188:30」 シリアル値「7.85416666666666」 しれっと質問文だけ編集して嘘つかれても困るし、協力する気がなくなります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.40%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問