ごまなつ Blog

楽しく働ける世界を目指して

【C#】UnixTimeの現在時刻変換でやらかした2点

UnixTimeから現在時刻に変換して表示をしていたのですが、2点やらかしたので、そのまとめです。

変換には以下を用いました。

 private readonly static DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long ToUnixTime(DateTime dateTime)
        {
            dateTime = dateTime.ToUniversalTime();
            TimeSpan elapsedTime = dateTime - UnixEpoch;
            return (long)elapsedTime.TotalSeconds;
        }
        public static string FromUnixTime(long unixTime)
        {
            return UnixEpoch.AddSeconds(unixTime).ToLocalTime().ToString("yyyy/MM/dd HH:mm");
        }

ToLocalTime()の書き忘れ

ToLocalTime()は現地時間への変換です。日本ではUTCと9時間ずれているため、変換しないと9時間ずれます。

カスタム日時形式文字列

docs.microsoft.com

DateTime.Now.ToString(””yyyy/MM/dd HH:mm:ss")のようなものです。よく使うのは、以下だと思います。

  • yyyy:4けたの年
  • yy:0埋め2けたの年
  • MM:0埋め2けたの月
  • dd:0埋め2けたの日
  • ddd:曜日の省略名
  • dddd:曜日の完全名
  • HH:0埋め2けたの時間(24時間表記)
  • hh:0埋め2けたの時間(12時間表記)
  • mm:0埋め2けたの分
  • ss:0埋め2けたの秒

現地時間に変換すると、どうしても12時間ずれました。なぜか。HHをhhと書いていました。24時間表記を期待しているのに12時間表記のため、午後に操作すると12時間ずれていました。また、日にちの部分にmmと書いてしまいました。

まとめ

UnixTimeは間違っていないのに、DateTimeに変換して表示するとなにかおかしい。そんなときには、現地時間への変換が行われているか、カスタム日時形式文字列は間違っていないか確認しようと思います。

「これからの生き方。」を読んだ

あなたの価値観はどのようなものですか?

これがこの本の主題だと感じました。生き方を自分の価値観に従ったものにすることで幸せに近づける、自分の価値観を知って生き方を考えようと語りかけられている気がしました。

概要

最初は漫画で、仕事への価値観が異なるキャラクター達の物語が展開されます。そのあと、価値観を知るワークがあり、著者自身の経験から感性を磨くことの大切さが書いてあります。

仕事への価値観

  1. 能力の活用(自分の能力を発揮できること)
  2. 達成(良い結果が生まれたという実感)
  3. 美的追求(美しいものを創り出せること)
  4. 愛他性(人の役に立てること)
  5. 自立性・自律性(自律できること)
  6. 創造性(新しいものや考え方を作り出せること)
  7. 経済的価値(たくさんのお金を稼ぎ、高水準の生活を送れること)
  8. ライフスタイル(自分の望むペース、生活ができること)
  9. 身体的活動(体を動かす機会が持てること)
  10. 社会的評価(社会に仕事の成果を認めてもらうこと)
  11. 危険性、冒涜性(わくわくするような体験ができること)
  12. 社会的交流(いろんな人と接点を持ちながら仕事をできること)
  13. 多様性(多様な活動ができること)
  14. 環境(仕事環境が心地よいこと)

これらの要素がそれぞれの人によって異なります。会社にはいろいろな人が存在するので、分かり合えないこともあります。それでも、うまくいくよう考えていかないとな、と思いました。

キャリアの型

スキル型、意志型、チーム型、バランス型が紹介されています。何を強みにするかで分類されています。それぞれ強みと弱みが書かれています。 自分は特徴を確認すると、当てはまっている部分と当てはまらない部分がすべてに存在していて、明確にこの型だと言い切れませんでした。 だからこそ、バランス型なのかもしれないですね。

感性を磨く

自分の感性や価値観を知っておかないと、どんなに若くても「人生を持て余す」感覚に陥るそうです。そうなると、生き方を問われる人になってしまいます。そのため、自分の感性を磨いて理解することを推奨しています。自分の感情や言動に対して、なぜこう思ったのか、なぜこうしたのかということを考えていくことで感性が磨かれます。

感想

読み終わった後、これから頑張ろうと思える本でした。勇気をもらえる本だと思います。

【C#】BinaryFormatterを用いた配列のコピーはかなり遅い

結論

配列をディープコピーしたいのであれば、一つずつコピーした方が良いです。

経緯

C#では、クラスの配列をArray.Copyしたときシャローコピーになります。正確に言うと、2階層目からシャローコピーになります。1次元の配列であれば、Array.Copyでディープコピーになりますが、リストのリストといった2階層目があると2階層目からシャローコピーになります。リストのリストをディープコピーしたかったので、このような方法を用いました。

public static T DeepCopyT<T>(T target)
        {
            T result;
            BinaryFormatter b = new BinaryFormatter();
            MemoryStream mem = new MemoryStream();

            try
            {
                b.Serialize(mem, target);
                mem.Position = 0;
                result = (T)b.Deserialize(mem);
            }
            finally
            {
                mem.Dispose();
            }

            return result;
        }

BinaryFormatterでMemoryStreamをシリアライズ・デシリアライズすることで、コピーしたものを返しています。 今回私がこのメソッドに渡していた配列は、class[1000]でした。クラスはa[23].b[20].c[8]個の構造でした。これを上記のメソッドに丸ごとクラスの配列を渡すと、 何と2分かかりました。さすがに実用に耐えないということで、対策を調べるとBinaryFormatterの配列のシリアライズ・デシリアライズは遅いということが分かりました。よって

for(int i=0;i<class.Length;i++)
{
          copyArray[i] = DeepCopy.DeepCopyT(class[i]);
}

として一つずつ渡すようにすると20秒で終わりました。

【C#】DataGridViewComboBoxを一度のクリックで開きたい

結論

F4を押す処理を追加する方法が出てくるが、F4はALTと同時押しするとアプリケーション終了になるなど、ショートカットキーに使われており何か起こる可能性があるのでお勧めしない。 CellEnterイベントで、DropedDownを使おう

private void DataGridView_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
            DataGridView dgv = (DataGridView)sender;
            if(dgv.Columns[e.ColumnIndex].Name == columnName 
            {
                dgv.BeginEdit(false);
                ((DataGridViewComboBoxEditingControl)dgv.EditingControl).DroppedDown = true;
            }
        }

経緯

現在作成しているフォームアプリでは、DataGridViewComboBoxColumnを追加しています。DataGridViewでコンボボックスのカラムを使うと、コンボボックスが開くまでに2回クリックしなければなりません。

  • 1回目のクリックでこのカラムがクリックされたか検知
  • 2回目のクリックでコンボボックスを開く

という処理になっているからです。これは直感に反するので、一回のクリックで開くようにする方法を調べました。すると、CellEnterイベントでSendKeys.Send("{F4}");する方法が見つかりました。これでもできたのですが、ALTを押しながらだとALT+F4となりアプリケーションが落ちるのでは?と考え実際にやってみると落ちました。F4はショートカットキーに使われるため、この方法は良くないと考え、DropedDownを使う方法を採用しました。

感想

処理は実現できたのですが、思わぬところで不具合が出ることがあるのでそこも想定したうえで採用する処理を考えていこうと思いました。

【C#】親フォームの中央に子フォームを表示したい

結論

親フォーム側で子フォームを呼び出すときに、

var frm = new Form1;
frm.Owner = this;
frm.StartPosition = FormStartPosition.CenterParent;

経緯

フォームアプリを作っており、子フォームにデータの内容を入力して、その内容を親フォームに反映するようにしていました。なにも設定せずに呼び出すと、子フォームが親フォームと離れた位置に表示されることがありました。よって、子フォーム側に

this.Location = new Point(
this.Owner.Location.X + (this.Owner.Width - this.Width) / 2,
this.Owner.Location.Y + (this.Owner.Height - this.Height) / 2);

を記載し、子フォームを表示したところ位置は親フォームの中心だったのですが、デュアルディスプレイの場合、サブディスプレイに親フォームを移動してから子フォームを表示すると、メインディスプレイに子フォームが表示されます(計算した座標は合っている)。

どちらのディスプレイに表示されているかを取得し、設定してもよかったのですが、調べていくうちに親フォーム側に設定することで実現できることが分かりました。それが

var frm = new Form1;
frm.Owner = this;
frm.StartPosition = FormStartPosition.CenterParent;

でした。呼び出す前(ShowDialogする前)に、親フォームは自分だと指定して、StartPositionを親の中心にする設定で実現できました。これなら、デュアルディスプレイでも親フォームの中心に子フォームが表示されます。

MessageBox

MessageBoxは、位置を指定するプロパティはなく、ディスプレイの中心に表示されます。位置を指定したいなら、拡張メソッドを書くしかないようです。

【C#】FolderBrowserDialogが使いにくいので、OpenFileDialog でフォルダを指定する

こちらの記事を参考にしています。 qiita.com

実現できるメソッド

void BrowseFolder()
{
    using (var ofd = new OpenFileDialog() { FileName = "SelectFolder", Filter = "Folder|.", CheckFileExists = false })
    {
        if (ofd.ShowDialog() == DialogResult.OK)
        {
            Console.WriteLine(Path.GetDirectoryName(ofd.FileName));
        }
    }
}

(参考記事から引用)

FolderBrowserDialog

  • 選択したフォルダのパスを取得
  • パス直打ちが無い
  • クイックアクセスが無い
  • フォルダを開いたときのツリー構造が見づらい

というところがあります。また、ファイル選択をする場面が多いため、OpenFileDialogのほうがイメージされやすく、その使い勝手を要求されます。よって、OpenFileDialogでフォルダ選択できるのが便利だと思われます。上記のメソッドを使えば、OpenFileDialog でフォルダのパスを取得することができます。

なぜFolderBrowserDialogはOpenFileDialogに変更要求を受けるのか

これはよく使われているのがOpenFileDialogであり、こちらをよく見慣れて・使い慣れているからだと考えます。FolderBrowserDialogにも良いところはあるのに、メジャーになっている方を求められるということではないでしょうか。

【C#】ドラッグ&ドロップが作動しないのは、権限が異なるため

ドラッグ&ドロップでファイルパスを取得する機能がWindowsアプリにあります。その機能を実装したにもかかわらず、VisualStudio上で動かしてもこの機能が動作しない。ドラッグ&ドロップできるときは、マウスカーソルが変化しますがそれすらも起こらない。調べた結果のメモです。

結論

VisualStudioをユーザ権限で開いてください(管理者権限で開かない)

経緯

以前開発していたアプリは、Windowsのサービスに追加されて常駐するものでした。Windowsのサービスに追加されるため、VisualStudioのデバッグ環境上でも毎回「VisualStudioが変更を加えることを許可しますか」のダイアログが出て煩わしかったため、VisualStudioを常に管理者権限で起動するように変更していました。

今回の状況は、権限が異なるアプリで、Windowsによって操作がブロックされています。VisualStudioが管理者権限で起動しているため、VisualStudioでのデバッグ環境で起動しているアプリは管理者権限、しかしフォルダエクスプローラはユーザ権限で開いているため、そこのフォルダからのドラッグ&ドロップは受け付けなかった、ということだと思われます。