Visual Studio / WPF > イベント > DispatcherTimerを使ったAlarm機能の試作 > DateTime.Now.Subtract() | .TotalSeconds | .Add(new TimeSpan(0, 0, 1)) | .AddSeconds(1)

```txt:動作環境
Windows 7 Pro (32bit)
Microsoft Visual Studio 2017 Community
Sublime Text 2
```

DispatcherTimerを使ってAlarm機能を実装しようとした。

### リンク


参考1: http://stackoverflow.com/questions/4946316/showing-difference-between-two-datetime-values-in-hours

## v0.1

### code

```MainWindow.xaml
<Window x:Class="_170502_t0615_timer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:_170502_t0615_timer"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock Name="T_timer" FontSize="32" Text="00:00:00"/>
    </Grid>
</Window>
```

```MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading; // for timer

namespace _170502_t0615_timer
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        DispatcherTimer myTimer;

        public MainWindow()
        {
            InitializeComponent();

            myTimer = new DispatcherTimer(DispatcherPriority.Normal);
            myTimer.Interval = new TimeSpan(0, 0, 1);
            myTimer.Tick += myTimer_Tick;
            myTimer.Start();
        }

        void myTimer_Tick(object sender, EventArgs e)
        {
            T_timer.Text = DateTime.Now.ToLongTimeString();

            var trigger = new DateTime(2017, 5, 2, 6, 27, 30);
            TimeSpan diff = DateTime.Now.Subtract(trigger);

            if (diff.Seconds == 0)
            {
                Console.WriteLine("Alarm");
            }
            Console.WriteLine("Tick");
        }
    }
}
```

### 結果

「出力」ウィンドウ。

```
...
Tick
Tick
Tick
Tick
Tick
Tick
Tick
Tick
Tick
Alarm
Tick
Alarm
Tick
```

Alarmが2回発行された。
バグっている。

### v0.2

Alarm時の日時を表示するように変更。

```MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading; // for timer

namespace _170502_t0615_timer
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        DispatcherTimer myTimer;

        public MainWindow()
        {
            InitializeComponent();

            myTimer = new DispatcherTimer(DispatcherPriority.Normal);
            myTimer.Interval = new TimeSpan(0, 0, 1);
            myTimer.Tick += myTimer_Tick;
            myTimer.Start();
        }

        void myTimer_Tick(object sender, EventArgs e)
        {
            T_timer.Text = DateTime.Now.ToLongTimeString();

            var trigger = new DateTime(2017, 5, 2, 6, 34, 30);
            TimeSpan diff = DateTime.Now.Subtract(trigger);

            if (diff.Seconds == 0)
            {
                Console.WriteLine("Alarm: on {0}", DateTime.Now.ToLongTimeString());
            }
            //Console.WriteLine("Tick");
        }
    }
}
```

```
Alarm: on 6:34:29
Alarm: on 6:34:30
```

Subtractしたときに1秒未満の誤差も`diff.Seconds==0`ということになっているようだ。

[c++ builder > TDateTime > SecondsBetween() > 秒未満の切捨てに注意をする](http://qiita.com/7of9/items/b885091b329a2a617538)
と同じような感じなのだろう。

### v0.3 

diff.TotalSeconds()を表示してみた。
1つのAlarm時刻だけだと少ないため、複数のAlarm時刻にした。

```MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading; // for timer

namespace _170502_t0615_timer
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        DispatcherTimer myTimer;

        public MainWindow()
        {
            InitializeComponent();

            myTimer = new DispatcherTimer(DispatcherPriority.Normal);
            myTimer.Interval = new TimeSpan(0, 0, 1);
            myTimer.Tick += myTimer_Tick;
            myTimer.Start();
        }

        void myTimer_Tick(object sender, EventArgs e)
        {
            T_timer.Text = DateTime.Now.ToLongTimeString();

            DateTime [] triggers = {
                new DateTime(2017, 5, 2, 6, 44, 30),
                new DateTime(2017, 5, 2, 6, 44, 32),
                new DateTime(2017, 5, 2, 6, 44, 34),
            };
            TimeSpan diff;
            
            foreach(var trg in triggers)
            {
                diff = DateTime.Now.Subtract(trg);
                if (diff.Seconds == 0)
                {
                    //Console.WriteLine("Alarm: on {0}", DateTime.Now.ToLongTimeString());
                    Console.WriteLine("Alarm: on {0}", diff.TotalSeconds.ToString());
                }
            }


            //Console.WriteLine("Tick");
        }
    }
}
```

```
Alarm: on -0.9639294
Alarm: on 0.0581291
Alarm: on -0.9318132
Alarm: on 0.0782446
Alarm: on -0.9046972
Alarm: on 0.1103608
```

diff.TotalSecondsを0.1未満で切り捨てるのはだめのようだ。

### v0.4 > 不等号使用案

http://stackoverflow.com/questions/10464743/is-there-a-better-way-to-set-an-alarm-clock-than-this
において不等号を使っている例があるのでそちらを使う。

```MainWindowXaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading; // for timer

namespace _170502_t0615_timer
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        DispatcherTimer myTimer;

        public MainWindow()
        {
            InitializeComponent();

            myTimer = new DispatcherTimer(DispatcherPriority.Normal);
            myTimer.Interval = new TimeSpan(0, 0, 1);
            myTimer.Tick += myTimer_Tick;
            myTimer.Start();
        }

        void myTimer_Tick(object sender, EventArgs e)
        {
            T_timer.Text = DateTime.Now.ToLongTimeString();

            DateTime [] triggers = {
                new DateTime(2017, 5, 2, 6, 51, 30),
                new DateTime(2017, 5, 2, 6, 51, 32),
                new DateTime(2017, 5, 2, 6, 51, 34),
            };
            
            foreach(var startdt in triggers)
            {
                var enddt = startdt.Add(new TimeSpan(0, 0, 1));
                if (DateTime.Now >= startdt && DateTime.Now < enddt) 
                {
                    Console.WriteLine("Alarm: on {0}", DateTime.Now.ToLongTimeString());
                }
            }


            //Console.WriteLine("Tick");
        }
    }
}
```

```
Alarm: on 6:51:30
Alarm: on 6:51:32
Alarm: on 6:51:34
```

成功したが、もっと良い方法は他にもありそうだ。

### v0.5 > AddSeconds()

https://msdn.microsoft.com/ja-jp/library/system.datetime(v=vs.110).aspx
や[過去の自分の記事](http://qiita.com/7of9/items/f444729198228f10e28e)を見ているとAddSeconds()というのが使えるようだ。

```csharp
// var enddt = startdt.Add(new TimeSpan(0, 0, 1));
var enddt = startdt.AddSeconds(1);
```