MySQL Connector/J 5.1 系では useLegacyDatetimeCode=false にしよう
JDBC で MySQL に接続するときに使用する MySQL Connector/J (mysql:mysql-connector-java) の話。 サーバー・クライアントのタイムゾーン設定が違っている場合にどう対応するのがいいか。
結論
- MySQL Connector/J 6 (まだ開発版だけど) 以降は自動でやってくれるので気にする必要はない。
- MySQL Connector/J 5.1 では URL に
useLegacyDatetimeCode=false
を入れて、時刻周りの新しい処理が動くようにしろ。- 新しい処理では、タイムゾーンの変換を一貫性をもってやってくれるようになる。
- 『Use code for DATE/TIME/DATETIME/TIMESTAMP handling in result sets and statements that consistently handles time zone conversions from client to server and back again』
- 参考 : 5.1 Driver/Datasource Class Names, URL Syntax and Configuration Properties for Connector/J
- 5.1 系ではデフォルトでは互換のために新しい処理は動かないようになっているので、明示的に新しい処理を使うように URL で指定する必要がある。
- バージョン 5.1.6 で導入された機能なので、それより古いものでは使えない。
問題
そもそもどういう問題に遭遇したのか。
- Java のアプリケーションサーバーのタイムゾーンが JST。
- MySQL サーバーのタイムゾーンが UTC。
- Java アプリケーションから MySQL サーバーには MySQL Connector/J 5.1 系で接続。
- タイムゾーン周りのオプションは何も指定せず。
- SQL 文の
NOW()
関数やDEFAULT CURRENT_TIMESTAMP
で設定された時刻を Java アプリケーション側で取得すると、現在時刻から 9 時間前の時刻が返ってきた。 - → MySQL Connector/J がサーバー・クライアント間のタイムゾーン差を扱ってくれてない。
MySQL Connector/J とタイムゾーン
- もともとは
useTimezone
プロパティやserverTimezone
プロパティを使って対応する必要があった。 - MySQL Connector/J 5.1.6 で時刻周りの処理が書き直されて、
useLegacyDatetimeCode=false
することでタイムゾーン変換などを自動で扱ってくれるようになった。 - MySQL Connector/J 6 では
useLegacyDatetimeCode
プロパティを含め、古いタイムゾーン周りのプロパティは全部削除される。
おわり
タイムゾーンはライブラリ側がちゃんと面倒見てくれるだろう、と思って気にしなかったら、環境を変えて Java アプリケーションと MySQL サーバーのタイムゾーン設定がずれたときにいきなり想定しない動作になったりするので気を付けましょう。
grunt-ts が .baseDir.ts ファイルを作るのを抑制する
Grunt を使っていて TypeScript のビルドを行うタスクを定義する際には grunt-ts を使うことが多いでしょう。 (grunt-typescript もあるけど。) grunt-ts で困ったことがあったので書いておきます。
outDir
オプションを使うと .baseDir.ts ファイルが作られる問題
grunt-ts を使って tsc
コマンドの --outDir
オプション指定を行うには outDir
プロパティが使えるのですが、この値を指定すると、何故か 「.baseDir.ts」 という名前のファイルがソースディレクトリの方に生成されてしまいます。
このファイルは何かというと、TypeScript 1.5 で --rootDir
オプションが導入される前に grunt-ts 独自に --rootDir
相当のことをするために導入されたものです。 grunt-ts のドキュメントを読む限り、baseDir
オプションを使っておらず、fast コンパイルが無効になっている場合には 「.baseDir.ts」 ファイルは作られないはずです。 しかしながら、grunt-ts 5.5.1 で試したところ、baseDir
オプションを使わず fast
オプションに "never"
を指定しても outDir
オプションを指定すると 「.baseDir.ts」 ファイルが作成されてしまいました。 個人的にはバグっぽいなーと思っています *1。 一応 pull request を投げておきました。
ちなみに以下のような Gruntfile.js (一部) で動作確認しました。
grunt.initConfig({ ts: { default: { src: ["src/ts/**/*.ts"], outDir: "build/ts" options: { fast: "never" } } } });
回避方法
現在 (バージョン 5.5.1) の grunt-ts に .baseDir.ts ファイルを作らせないようにする方法はいくつかあります。
outDir
オプションではなく additionalFlags
で --outDir
オプションを指定する
grunt-ts は outDir
オプションを見て 「.baseDir.ts」 ファイルを生成するかどうか決めているので、additionalFlags
の方で --outDir
を指定すると 「.baseDir.ts」 ファイルは生成されません。
grunt.initConfig({ ts: { default: { src: ["src/ts/**/*.ts"], options: { additionalFlags: "--outDir build/ts" } } } });
tsconfig.json ファイルを指定する
tsconfig.json の中で outDir
オプションを指定し、grunt-ts には tsconfig
プロパティで tsconfig.json のパスを指定教えるだけにするという方法もあります。 ただし、普通に指定するだけでは tsconfig.json を解析して grunt-ts が余計なことをするっぽい (tsconfig.json 側で outDir
オプションを指定していると、grunt-ts が .baseDir.ts ファイルを作ってしまう) ので、passThrough
オプションを有効にして、grunt-ts が余計なことをしないようにする必要があります。
grunt.initConfig({ ts: { default: { tsconfig: { tsconfig: "src/ts/tsconfig.json", // このファイルの中でコンパイル対象のファイル群や `outDir` 指定を行う passThrough: true } } } });
おわり
こんなしょうもないことをやってるのは無駄だと思うし grunt-ts はオススメしません。
関連ページ
- Stop creating .baseDir.ts file · Issue #300 · TypeStrong/grunt-ts · GitHub :
rootDir
オプションが有効なら .baseDir.ts ファイルを生成しないとかしてもいいのでは、みたいな話がされてる。 - TypeScript needs a `baseDir` option · Issue #77 · TypeStrong/grunt-ts · GitHub :
baseDir
オプションが導入されることになった経緯。
*1:ドキュメントの記述から察するに仕様ではなさそうだし、コードの実装も微妙に変なので
UWP アプリ 「みお×ぽん」 のバージョン 1.1.0 をリリースしました
2016 年 10 月 1 日、IIJmio の 「IIJmio 高速モバイル / D サービス」 が au の回線にも対応して 「IIJmio モバイルサービス」 に改称されました。
それに合わせて、「IIJmio モバイルサービス」 のクーポン切り替えを行うことができる UWP アプリ 「みお×ぽん」 をバージョンアップしました。
文言変更や一部デザイン変更、バグ修正のみであんまり大きな変更はしていないのですが、ご利用くださっている方はバージョンアップしてくださいませ。
変更内容
ちなみに公式アプリもあるよ
「みお×ぽん」 の最初のリリース時には IIJ による公式の UWP アプリはなかったのですが、2016 年 6 月ごろに公式アプリがリリースされました。
先ほど、Windows10版(UWP版)のIIJmioクーポンスイッチアプリ(みおぽん)をリリースしました。Windows10のインストールされたPC、およびWindows10 Mobileのスマートフォン等でご利用になれます。https://t.co/rawRYSL0wX
— IIJmio (@iijmio) June 3, 2016
やったぜ!
*1:昔の MS のサンプルプロジェクト通りの実装だとだめっぽい。 これに関してはまた書こうと思う。
レスポンシブデザインのために resize イベントを使うのはやめて matchMedia メソッドを使おう
レスポンシブデザインのために CSS メディアクエリを使うことが多いと思います。 CSS 側だけで完結したらいいのですが、JavaScript 側でも画面サイズの変更を検知したかったり、画面サイズ以外のメディアクエリ相当のことをしたくなったりすることはありますよね。
画面サイズの変更自体は window
に発生する resize
イベント (window.onresize
イベントハンドラ) で検知できますが、CSS メディアクエリとこれを組み合わせてレスポンシブ対応しようとすると以下の問題がでてきます。
- ウィンドウサイズ変更時に
resize
イベントが高頻度で発生するので、resize
イベントのリスナでコストのかかる処理を行うのはよくないとされる。 (Throttling することが推奨される。)- 参考 : resize | MDN
- CSS メディアクエリと完全に対応するものではないので、CSS 側との対応を取りづらい。
上の方はまあ throttling すればいいのですが、下の問題はどうしようもないですね。
window.matchMedia
メソッドと MediaQueryList
そこで別の方法としておすすめしたいのが window.matchMedia
メソッドとその返り値の MediaQueryList
オブジェクトです。 標準化についてはまだ完了しておらず、CSSOM View Module で作業されているようです。 とはいえ最近のブラウザだとどのブラウザでも使えるみたいなので、実用的に使っていける状況になっているかと思います。 (IE 9 とか少し古めの Android のブラウザとかでは使えないので、そこら辺のサポートが必要ならまだ使えませんが><)
window.matchMedia
メソッドの引数としてメディアクエリのリスト (media query list: メディアクエリをカンマ区切りで繋げたもの) を渡すと、それらのメディアクエリのリストを表す MediaQueryList
オブジェクトが返されます。 MediaQueryList#matches
プロパティを使うことで、リスト中のメディアクエリのうち少なくとも 1 つ以上が真になっているか、もしくはすべてが偽であるかを判別できます。
また、MediaQueryList#addListenr
メソッドでイベントリスナを設定することで、matches
の値の変化を検知することができます。
// TypeScript です。 // 縦 600px 以下、または横 600px 以下の場合に matches state が真になるメディアクエリリスト。 var mql = window.matchMedia("(max-width: 600px), (max-height: 600px)"); // メディアクエリリストの matches state に応じた処理を行う関数。 function handleMediaQueryListMatchesState(matches: boolean) { if (matches) { // メディアクエリリストの matches state が真の場合の処理。 } else { // 偽の場合の処理。 } } // イベントリスナを設定して matches state の変化を検知。 mql.addListener((evt) => handleMediaQueryListMatchesState(evt.matches)); // 初期化。 handleMediaQueryListMatchesState(mql.matches);
便利ですね。 非対応ブラウザを切っていいようでしたらどんどん使っていきましょう。
歴史的経緯?
ところで MediaQueryList
は addEventListener
メソッドを持っているはずなのに、それとは別に addListener
メソッドも持っていてどうなってるんだろう、と思いますよね。 私も思いました。 どうやら昔は MediaQueryList
は独自のコールバックの仕組みを使っていて、addEventListener
を持っていなかったようです。 また、コールバックメソッドに引数として渡される値も MediaQueryListEvent
ではなく、MediaQueryList
オブジェクトがそのまま渡されていたようです。
Note: This specification initially had a custom callback mechanism with
CSSOM View Module, 4.2. The MediaQueryList InterfaceaddListener()
andremoveListener()
, and the callback was invoked with the associated media query list as argument. Now the normal event mechanism is used instead. For backwards compatibility, theaddListener()
andremoveListener()
methods are basically aliases foraddEventListener()
andremoveEventListener()
, respectively, and the change event masquerades as aMediaQueryList
.
実際に試したところ、Firefox 49.0.1 や Edge 38.14393.0.0 では古い挙動になっていました。 Chrome 53.0.2785.116m は最新の CSSOM View Module にあった実装になっていました。 Firefox や Edge の実装はまだ最新の CSSOM View Module にあった実装になっていないので、しばらくは addListener
メソッドを使っていくようにするのが良さそうです。
他の方法
CSS 側でメディアクエリを使って特定要素のプロパティを変更するなどして、JS 側からはそのプロパティを見ることでどのメディアクエリが有効になってるのか検査するのが今のところは安定、という話も。 IE 9 や古めの Android 端末をサポートするならそういう方法が良さそうです。 (ということですよね? 他の理由があるなら教えてください!)
レスポンシブデザインのために resize イベントを使うのはやめて matchMedia メソッドを使おう - ひだまりソケットは壊れない今はまだ画面サイズ検知用の要素作って、font-familyとかをメディアクエリで変更するのが一番楽かな。font-family: "sp";とか。resizeイベント側はfont名を見るだけ。ただイベントで変化を検知できるのはいいなぁ
2016/10/02 14:57
matchMedia使うよりも対象メディアクエリ内で特定要素のdisplsyプロパティを検査した方が安全で簡単な場合が多いかな。https://t.co/WZ3VhfpJfQ
— h. kitago (@hkitago) October 2, 2016
参考
- CSSOM View Module : 標準化作業中の文書。
- 本記事記述のために参考にしたバージョンは こちら。
- スクリプトからのメディアクエリの使用 - ウェブデベロッパーガイド | MDN : MDN 上の
matchMedia
メソッドとMediaQueryList
の説明。 - Responsive Web Design Basics | Web | Google Developers : レスポンシブデザインの全体的な話。 (JS 上でのメディアクエリの話はないけど参考に。)
- Media Queries : メディアクエリについての W3C 勧告。
- GitHub - paulirish/matchMedia.js: matchMedia polyfill for testing media queries in JS :
matchMedia
の polyfil。 - ブログ記事もいくつかあります。
- JavaScript でメディアクエリを行う window.matchMedia の使い方 | Mozilla Developer Street (modest)
- やるやんwindow.matchmedia - FICC Workbook
- $(window).resize()は使わず、window.matchMediaを使って、jsでのメディアクエリー的な事をしてみよう的なお話 ~ 適当な感じでプログラミングとか! : サンプルコードで、毎回
matchMedia
メソッドを呼んでるのが微妙。 - レスポンシブWeb制作時に便利なmatchMediaメソッド | while(isプログラマ) : サンプルコード中に 「イベントリスナで実行された場合は、必ずtrue」 って書かれてるけど実際はそんなことはない。
- matchMediaを使ってみる | cly7796.net :
resize
イベントのリスナの中でmatchMedia
メソッドを使っていて微妙。
PowerShell (Windows) で Docker コンテナにホストディレクトリをデータボリュームとしてマウントする際に pwd 相当のことをしたい
試した環境
- Windows 10 Home (Anniversary Update; 64-bit 版)
- Docker Toolbox 1.12.0
前提知識
docker run -v /path/of/host/dir:/path/of/container ...
という感じでホストディレクトリをデータボリュームとしてマウントできる。- Windows で Docker Engine を使う場合、ホストディレクトリのパスは 「/c/Users/.../...」 という形式で記述する。
- バージョン 1.10 のドキュメント 参照。
- 最新のドキュメント では 「c:\Users\...\...」 という表記になっているが、これがあってるのか間違ってるのかは不明。 Windows で Dockcer Toolbox 1.12.0 を試した限りではだめだった。
- ホストディレクトリのパスは絶対パスで記述する必要がある。
絶対パスで記述するためにどうするかが問題
Linux では以下のように pwd
コマンドを使うのが一般的かと思います。
docker run -v $(pwd)/path/to/target:/container/path ...
じゃあ Windows (PowerShell) でどうするのか、というのが問題です。 PowerShell にも pwd
コマンド相当の Get-Location
コマンドレット があるのですが、これをそのまま使うとパスの形式が通常の Windows のパス表記の形式になるので、docker
コマンドの -v
オプションに渡せません。
Write-Output "$(Get-Location)/path/to/target" # => C:\Users\userName\Documents\project/path/to/target # 本当は /c/Users/userName/Cocuments/project/path/to/target という形式で欲しい # 実際にやってみると以下のようなエラーが出る。 docker run -v "$(Get-Location)/path/to/target:/container/path" ... C:\Program Files\Docker Toolbox\docker.exe: Error response from daemon: Invalid bind mount spec "C:\\Users\\userName\\Documents\\project/path/to/target:/container/path": invalid mode: /container/path. See 'C:\Program Files\Docker Toolbox\docker.exe run --help'.
雑に対応する
そんなわけで、以下のように Windows の通常のパスの表記を Linux ぽい感じに変換する関数を定義して使っています。
function pwd_as_linux { "/$((pwd).Drive.Name.ToLowerInvariant())/$((pwd).Path.Replace('\', '/').Substring(3))" } # 実際使う場合は以下のような感じ。 docker run -v "$(pwd_as_linux)/path/to/target:/container/path" ...
関数を定義するまでもなく変数に格納して使いたいって感じなら以下のようにもできます。
# Linux 風のパス形式。 $pwd_as_linux = "/$((pwd).Drive.Name.ToLowerInvariant())/$((pwd).Path.Replace('\', '/').Substring(3))" # 使う。 docker run -v ${pwd_as_linux}/path/to/target:/container/path ...
Docker Engine 側で通常の Windows のパス形式を受け付けてくれたらいいのですが、コロンが区切りに使われてるから難しいんだろうなぁと思ったり。
参考ページ
- Manage data in containers : 最新 (?) の公式ドキュメント。 コンテナ内のデータの管理について。
- Manage data in containers : バージョン 1.10 の公式ドキュメント。 基本的には上と同じはず。
- Dockerにホストのフォルダをマウントしたい! - Qiita : Windows でホストディレクトリをデータボリュームとしてマウントする話。
- Data Volume と Data Volume Container - Qiita : データボリューム全般に関して。
- Dockerコンテナからのディレクトリアクセスやボリューム共有 | Think IT(シンクイット) : データボリューム全般に関して。