かきスタンプ

福岡でフリーランスの物流系のエンジニアやってます。

1月31日の1ヶ月後は何日? 3月31日の1ヶ月前は何日? 各種RDBで確認してみた。

『期限切れとなるのは、登録日より1ヶ月後です』
『1か月前に告知されます』
というのを見た時、「何日だろ?」と思ったのがきっかけ。
   
法的に決められたルールや、国際ルールがあるんかな。
パッとググってみた感じ、見つけきれなかったんで、RDBに聞いてみた。
 
試したのは、以下。

RDBにて、同じ結果となりました。

結果

確認した内容 結果
1/28 の1か月後 2/28
1/29 の1か月後 2/28
1/30 の1か月後 2/28
1/31 の1か月後 2/28
3/28 の1か月前 2/28
3/29 の1か月前 2/28
3/30 の1か月前 2/28
3/31 の1か月前 2/28
1/28 の1か月後(うるう年) 2/28
1/29 の1か月後(うるう年) 2/29
1/30 の1か月後(うるう年) 2/29
1/31 の1か月後(うるう年) 2/29
3/28 の1か月前(うるう年) 2/28
3/29 の1か月前(うるう年) 2/29
3/30 の1か月前(うるう年) 2/29
3/31 の1か月前(うるう年) 2/29

発行したSQL

MySQL

ver:5.7

SELECT
    DATE_ADD(CAST('2018/01/28' AS DATE), INTERVAL 1 MONTH) AS "1/28 の1か月後"
   ,DATE_ADD(CAST('2018/01/29' AS DATE), INTERVAL 1 MONTH) AS "1/29 の1か月後"
   ,DATE_ADD(CAST('2018/01/30' AS DATE), INTERVAL 1 MONTH) AS "1/30 の1か月後"
   ,DATE_ADD(CAST('2018/01/31' AS DATE), INTERVAL 1 MONTH) AS "1/31 の1か月後"

   ,DATE_ADD(CAST('2018/03/28' AS DATE), INTERVAL -1 MONTH) AS "3/28 の1か月前"
   ,DATE_ADD(CAST('2018/03/29' AS DATE), INTERVAL -1 MONTH) AS "3/29 の1か月前"
   ,DATE_ADD(CAST('2018/03/30' AS DATE), INTERVAL -1 MONTH) AS "3/30 の1か月前"
   ,DATE_ADD(CAST('2018/03/31' AS DATE), INTERVAL -1 MONTH) AS "3/31 の1か月前"

   ,DATE_ADD(CAST('2020/01/28' AS DATE), INTERVAL 1 MONTH) AS "2/28 の1か月後(うるう年)"
   ,DATE_ADD(CAST('2020/01/29' AS DATE), INTERVAL 1 MONTH) AS "2/29 の1か月後(うるう年)"
   ,DATE_ADD(CAST('2020/01/30' AS DATE), INTERVAL 1 MONTH) AS "2/30 の1か月後(うるう年)"
   ,DATE_ADD(CAST('2020/01/31' AS DATE), INTERVAL 1 MONTH) AS "2/31 の1か月後(うるう年)"

   ,DATE_ADD(CAST('2020/03/28' AS DATE), INTERVAL -1 MONTH) AS "3/28 の1か月前(うるう年)"
   ,DATE_ADD(CAST('2020/03/29' AS DATE), INTERVAL -1 MONTH) AS "3/29 の1か月前(うるう年)"
   ,DATE_ADD(CAST('2020/03/30' AS DATE), INTERVAL -1 MONTH) AS "3/30 の1か月前(うるう年)"
   ,DATE_ADD(CAST('2020/03/31' AS DATE), INTERVAL -1 MONTH) AS "3/31 の1か月前(うるう年)"

PostgreSQL

ver:9.6

SELECT
    CAST('2018/01/28' AS DATE) + interval '1 months' AS "1/28 の1か月後"
   ,CAST('2018/01/29' AS DATE) + interval '1 months' AS "1/29 の1か月後"
   ,CAST('2018/01/30' AS DATE) + interval '1 months' AS "1/30 の1か月後"
   ,CAST('2018/01/31' AS DATE) + interval '1 months' AS "1/31 の1か月後"
   
   ,CAST('2018/03/28' AS DATE) + interval '-1 months' AS "3/28 の1か月前"
   ,CAST('2018/03/29' AS DATE) + interval '-1 months' AS "3/29 の1か月前"
   ,CAST('2018/03/30' AS DATE) + interval '-1 months' AS "3/30 の1か月前"
   ,CAST('2018/03/31' AS DATE) + interval '-1 months' AS "3/31 の1か月前"   
   
   ,CAST('2020/01/28' AS DATE) + interval '1 months' AS "1/28 の1か月後(うるう年)"
   ,CAST('2020/01/29' AS DATE) + interval '1 months' AS "1/29 の1か月後(うるう年)"
   ,CAST('2020/01/30' AS DATE) + interval '1 months' AS "1/30 の1か月後(うるう年)"
   ,CAST('2020/01/31' AS DATE) + interval '1 months' AS "1/31 の1か月後(うるう年)"
   
   ,CAST('2020/03/28' AS DATE) + interval '-1 months' AS "3/28 の1か月前(うるう年)"
   ,CAST('2020/03/29' AS DATE) + interval '-1 months' AS "3/29 の1か月前(うるう年)"
   ,CAST('2020/03/30' AS DATE) + interval '-1 months' AS "3/30 の1か月前(うるう年)"
   ,CAST('2020/03/31' AS DATE) + interval '-1 months' AS "3/31 の1か月前(うるう年)"

SQL Server

ver:14.0

SELECT
    DATEADD(MONTH, 1, CAST('2018/01/28' AS DATE)) AS "1/28 の1か月後"
   ,DATEADD(MONTH, 1, CAST('2018/01/29' AS DATE)) AS "1/29 の1か月後"
   ,DATEADD(MONTH, 1, CAST('2018/01/30' AS DATE)) AS "1/30 の1か月後"
   ,DATEADD(MONTH, 1, CAST('2018/01/31' AS DATE)) AS "1/31 の1か月後"

   ,DATEADD(MONTH, -1, CAST('2018/03/28' AS DATE)) AS "3/28 の1か月前"
   ,DATEADD(MONTH, -1, CAST('2018/03/29' AS DATE)) AS "3/29 の1か月前"
   ,DATEADD(MONTH, -1, CAST('2018/03/30' AS DATE)) AS "3/30 の1か月前"
   ,DATEADD(MONTH, -1, CAST('2018/03/31' AS DATE)) AS "3/31 の1か月前"

   ,DATEADD(MONTH, 1, CAST('2020/01/28' AS DATE)) AS "1/28 の1か月後(うるう年)"
   ,DATEADD(MONTH, 1, CAST('2020/01/29' AS DATE)) AS "1/29 の1か月後(うるう年)"
   ,DATEADD(MONTH, 1, CAST('2020/01/30' AS DATE)) AS "1/30 の1か月後(うるう年)"
   ,DATEADD(MONTH, 1, CAST('2020/01/31' AS DATE)) AS "1/31 の1か月後(うるう年)"

   ,DATEADD(MONTH, -1, CAST('2020/03/28' AS DATE)) AS "3/28 の1か月前(うるう年)"
   ,DATEADD(MONTH, -1, CAST('2020/03/29' AS DATE)) AS "3/29 の1か月前(うるう年)"
   ,DATEADD(MONTH, -1, CAST('2020/03/30' AS DATE)) AS "3/30 の1か月前(うるう年)"
   ,DATEADD(MONTH, -1, CAST('2020/03/31' AS DATE)) AS "3/31 の1か月前(うるう年)"

Oracle

ver:11g

SELECT
    ADD_MONTHS(TO_DATE('2018/01/28'), 1) AS "1/28 の1か月後"
   ,ADD_MONTHS(TO_DATE('2018/01/29'), 1) AS "1/29 の1か月後"
   ,ADD_MONTHS(TO_DATE('2018/01/30'), 1) AS "1/30 の1か月後"
   ,ADD_MONTHS(TO_DATE('2018/01/31'), 1) AS "1/31 の1か月後"
    
   ,ADD_MONTHS(TO_DATE('2018/03/31'), -1) AS "3/28 の1か月前"
   ,ADD_MONTHS(TO_DATE('2018/03/31'), -1) AS "3/29 の1か月前"
   ,ADD_MONTHS(TO_DATE('2018/03/31'), -1) AS "3/30 の1か月前"
   ,ADD_MONTHS(TO_DATE('2018/03/31'), -1) AS "3/31 の1か月前"
   
   ,ADD_MONTHS(TO_DATE('2020/01/28'), 1) AS "1/28 の1か月後(閏年)"
   ,ADD_MONTHS(TO_DATE('2020/01/29'), 1) AS "1/29 の1か月後(閏年)"
   ,ADD_MONTHS(TO_DATE('2020/01/30'), 1) AS "1/30 の1か月後(閏年)"
   ,ADD_MONTHS(TO_DATE('2020/01/31'), 1) AS "1/31 の1か月後(閏年)"
    
   ,ADD_MONTHS(TO_DATE('2020/03/31'), -1) AS "3/28 の1か月前(閏年)"
   ,ADD_MONTHS(TO_DATE('2020/03/31'), -1) AS "3/29 の1か月前(閏年)"
   ,ADD_MONTHS(TO_DATE('2020/03/31'), -1) AS "3/30 の1か月前(閏年)"
   ,ADD_MONTHS(TO_DATE('2020/03/31'), -1) AS "3/31 の1か月前(閏年)"
FROM 
    DUAL

マークダウンで簡単にスライドが作れるサービス『GitPitch』の使い方(応用編)

GitHubアカウントがあれば、マークダウンでお手軽にスライドが作れるサービス「GitPitch」の使い方(応用編)を、スライドにしてみた。

https://gitpitch.com/kakisoft/HowToUseGitPitch3 f:id:kakisoft:20180913003110p:plain

GitPitchを使ってどんな事ができるのか、直感的に分かるようにしてみました。
 
第一弾として作成した、基本編はこちらです。
https://gitpitch.com/kakisoft/HowToUseGitPitch
f:id:kakisoft:20170706210414p:plain  
 
また、Font Awesome から提供されているアイコンが自由に使えるようになっていますが、全てを使えるわけではないようです。

どれが使えて、どれが使えないか分からなかったので、とりあえず全部並べてみました。
https://gitpitch.com/kakisoft/GitPitchIconList

↓こんな感じで一覧できるようにしています。
f:id:kakisoft:20180913003117p:plain

Vagrant:IPアドレスを振っていない仮想マシンに sshログインする方法

<環境>
ホストOS:Windows 10
ゲストOS:CentOS 7
仮想化ツール:VirtualBox
sshクライアントツール:Tera Term


Vagrantで作成した仮想マシンは、通常「vagrant ssh」コマンドでログインするかと思いますが、通常の sshログインも可能です。
 
以下、デフォルト設定で仮想マシンを立上げ、Vagrantfile は特に編集していない状態を想定しています。

Tera Teamを起動

設定は以下。

f:id:kakisoft:20180818225639p:plain

ユーザ名・パスフレーズを設定

f:id:kakisoft:20180818225653p:plain
続いて、秘密鍵を設定します。

秘密鍵を設定

秘密鍵のパスは、

(仮想マシンを作成したフォルダ)\.vagrant\machines\default\virtualbox

となっています。
種類を「すべてのファイル」にして、『private_key』を選択します。 f:id:kakisoft:20180818225707p:plain

ログイン

f:id:kakisoft:20180818225716p:plain


備考

以下のコマンドで、ssh 設定を確認できます。

vagrant ssh-config

f:id:kakisoft:20180820002851p:plain

Linux:アクセス有効期限って、2種類あったんだね。って事に気が付いたんで、整理してみた。

以下のコマンドで、ユーザアカウントの有効期限の状態を確認できる。

chage --list ユーザー名

出力例

[kakisoft@localhost ~]$ chage --list kakisoft
Last password change                             : Aug 06, 2018
Password expires                                 : Sep 05, 2018
Password inactive                                : never
Account expires                                  : Dec 12, 2017
Minimum number of days between password change   : 0
Maximum number of days between password change   : 30
Number of days of warning before password expires: 7

出力例(日本語ver)

[kakisoft@localhost ~]$ chage --list kakisoft
最終パスワード変更日                    : 8月 06, 2018
パスワード期限:                        : 9月 05, 2018
パスワード無効化中                     : なし
アカウント期限切れ                     : 12月 12, 2018
パスワードが変更できるまでの最短日数     : 0
パスワードを変更しなくてよい最長日数     : 30
パスワード期限が切れる前に警告される日数 : 7

 
 
有効期限には、以下の2種類がある。

アカウントの有効期限

この日にちが経過すると、アカウントがロックされて使用不可となる。
パスワードの有効期限とは無関係。

(アカウント有効期限が切れたユーザでログインした時のメッセージ例)
Your account has expired; please contact your system administrator

以下のコマンドで、アカウントの有効期限を設定できる。

sudo chage -E YYYY-MM-DD ユーザ名

有効期限を無期限にするには、日付の代わりに -1 を入力する。

sudo chage -E -1 ユーザ名

「-E 0」と入力すると、有効期限が 1970/01/01 となり、ログインが出来なくなります。

パスワードの有効期限

この日にちが経過すると、登録したパスワードではアクセスできなくなる。

(パスワード有効期限が切れたユーザでログインした時のメッセージ例)
You are required to change your password immediately (root enforced)

※パスワードの変更が促される。

以下のコマンドで、パスワードの有効期限を変えることができる。

<パスワードの有効期限の指定(単位は日)。以下では有効期限を 30日に設定>
sudo chage -M 30 ユーザ名

-M以降の数字を「10000」以上にすると、パスワードの有効期限を無期限に設定できる。

有効期限が切れる日にちは、「Last password change(最終パスワード変更日)」を起点に、上記の日数を足した日付となる。 「Last password change(最終パスワード変更日)」は、以下のコマンドで変更できる。

sudo chage -d YYYY-MM-DD ユーザ名

C#:Visual Studioを使って、コードの複雑度を測定する方法。

Visual Studioを使って、コードの複雑度を測定する方法。
ブラックボックスが多い、未知のプロジェクトに着手する時の指標に。

1.

メニューから[分析]→[コードメトリックスを計算する]を選択する。
(ソリューション単位で計測するか、プロジェクト単位で計測するかはお好みで。) f:id:kakisoft:20180725205149p:plain

2.

こんな感じで計測結果が出てくる。 f:id:kakisoft:20180725205206p:plain

パラメータ解説

保守容易性指数

0 ~ 100 で表現される。値が大きいほど保守容易性が高い。

内容
0 ~ 9 レッドゾーン
10 ~ 19 中程度
20 ~ 100 安全な範囲

※あくまで「計測結果の判定はそうなっている」というだけで、実際に保守性が高いかどうかは、エンジニア自身で確認した方がいいです。  

サイクロマティック複雑度

値が大きいほど複雑度が高い。
目標値 200以下、どれだけ複雑でも 1000以下を目標にするとよいらしい。(知人のフリーランス談)

継承の深さ

そのまんま。
値が低い方が保守性が高い事が多い。

クラス結合度

そのまんま。
値が低い方が保守性が高い事が多い。

コード行

正直、正確な数字ではないため、極端に大きくないかどうかを確認する程度でいいと思う。

また、上記の指標は▽のマークを展開していく事で、メソッド単位でチェックすることも可能です。

チェックするポイント

主観も入っていますので、参考にする場合はご留意を。

ヤバいコードの検出

サイクロマティック複雑度の高い順にソートする。(ヘッダを選択すると、ソートできる)

サイクロマティック複雑度が高くても、保守容易性指数が高かったら、マトモなコードの可能性はある。
サイクロマティック複雑度が高く、保守容易性指数が低い場合、ほぼ確実にヤバいコード。

保守容易性指数は判定が甘い(「?」というようなコードでも、高めの数字は出やすい)ので、 サイクロマティック複雑度が高いソースについては、メソッド単位での確認もしておいた方がいい。

状況によって見るポイントを変えるパラメータ

「クラス結合度」は、画面系の場合は値が大きくなりやすい。
具体的には、テキストボックスやラジオボタンが大量に配置されていると、数字が大きくなりやすい。
なので、数字が大きくても複雑度がそれほど高くない事がある。  
が、それ以外の場合で「クラス結合度」が高い場合は危険率が高め。

参考程度にする情報

継承の深さ

もちろん値が小さい方がいいんだけど、1つのファイルに複数のクラスを記述し、ユーティリティクラスの塊のような書き方をしていると、 1つ1つのクラスの深さは大したことは無くても、数字が大きくなることがある。 (継承の数は、各クラスごとの数が累計された数字となる。)

が、そうでない場合は、複雑度は高い場合が多い。 10以上はデンジャーゾーン。

クラス結合

クラス単位でみると、内包するメソッドの累計が出てくるので、メソッド単位でチェックした方がいいと思う。
20以上からは注意、30以上からは警戒、40以上はレッドゾーン(の可能性が高い)。  
 
 


(公式サイトでの説明はこちら)
https://msdn.microsoft.com/ja-jp/library/bb385914.aspx

C#(MVVM):Vとバインドしたプロパティに対して VM側で値を変更する処理を記述する場合、アクセサでなくプライベート変数に変更をかけた方がいいのではないかという話。

Vとバインドしたプロパティに対して VM側で値を変更する処理を記述する場合、アクセサでなくプライベート変数に変更をかけた方がいいのではないかという話。    
 
以下、サンプルソースです。
今回の話題に必要なパートのみを抜粋した状態です。

<TextBox 
    Text="{Binding Path=MyVmString01, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
    />

<Button
    Content="AddText" 
    Command="{Binding Path=AddTextCommand}" 
    />
/// <summary>
/// プロパティ
/// </summary>
private string _myVmString01 = "初期値";
public string MyVmString01
{
    get
    {
        return this._myVmString01;
    }
    set
    {
        if (this._myVmString01 == value)
        {
            return;
        }
        this._myVmString01 = value;
        base.OnPropertyChanged(nameof(this.MyVmString01));
    }
}

/// <summary>
/// リレーコマンド
/// </summary>
private RelayCommand _addTextCommand;
public RelayCommand AddTextCommand
{
    get
    {
        return this._addTextCommand = this._addTextCommand ?? new RelayCommand(this.AddSpecialCharacter);
    }
}

/// <summary>
/// メソッド
/// </summary>
private void AddSpecialCharacter()
{
    _myVmString01 += "x";
    OnPropertyChanged(nameof(this.MyVmString01));
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string info)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
}

 

概要

  • MyVmString01 は、V側の TextBox とバインドしている。
  • MyVmString01 の変更は、アクセサを通して V側に通知される。(OnPropertyChangedメソッド。)
  • AddTextCommand は、V側の Button とバインドしている。
  • AddTextCommand から AddSpecialCharacter() がコールされ、_myVmString01 の内容が変更される。

 
 
話がしたいのは、AddSpecialCharacter() メソッド。
myVmString01 += "x" 』と、プライベート変数の myVmString01 に変更を加えているけど、「別に『MyVmString01 += "x";』と書いても結果は一緒だから、どっちでもいいんじゃね?」と思ってた。
 
が、setterを使うと 変更をV側に伝えるために OnPropertyChangedが実行される事になり、V側に渡す内容を取得するために getも実行される。 (getアクセサにブレークポイントを置くと分かりやすい。)
 
つまり、メソッドに 1000回書き換えるループ処理があれば、1000回 V側に通知され、1000回 getが実行される。

非常にメモリに優しくないので、プライベート変数を編集した後、OnPropertyChanged をコールすると、getが1回で済む。
もしくは編集用の一時変数を用意して、最後にアクセサをコールするという方法でもいいかも。

C#(MVVM):ソースコードにてバインディング設定する方法

xamlでなく、ソースからバインド設定をするには、SetBinding メソッドを使用します。

(例)

Button myButton01 = new Button();
// Content に「MyString01」というプロパティとのバインディング設定を追加
myButton01.SetBinding(Button.ContentProperty, nameof(MyString01));
// Command に「SaveCommand」というリレーコマンドとのバインディング設定を追加
myButton01.SetBinding(Button.CommandProperty, nameof(SaveCommand));

//あとは適当に配置。

「MyString01」という stringを返すプロパティと、
「SaveCommand」というリレーコマンドが定義済みとしています。
 
 
上記のソースは、以下のような Xamlを記述した場合と同じ動きをします。

<Button
    Content="{Binding Path=MyString01}"
    Command="{Binding Path=SaveCommand}" 
    />

 
 
SetBinding の第二引数に、バインディングの対象にしたい”文字列”を設定します。
なので、上記のソースは、以下のように書くこともできます。

myButton01.SetBinding(Button.ContentProperty, "MyString01");
myButton01.SetBinding(Button.CommandProperty, "SaveCommand");

 
ただ、この書き方だと、リファクタリングに弱くなり、コードジャンプ機能も使えないので、nameof を使用した方がメンテナンス時の労力を軽減できます。