tanamonの稀に良く書く日記

KEEP CALM AND DRINK BEER

緯度経度の省略はlat/lng、lat/lon、lat/longのどれが多数派なのか

タイトルのとおりなのですが、気になったので調べてみました。

ちなみに、調べる前はlat/lng派でした。

Google Trendsで比較

省略しないlatitude/longitudeを加えてGoogle Trendsで比較してみました。

f:id:tanamon:20190710175931p:plain https://trends.google.co.jp/trends/explore?date=today%205-y&q=lat%2Flon,lat%2Flng,lat%2Flong,latitude%2Flongitude

結果はlat/long >>> latitude/longitude > lat/lon >>> lat/lngでした。

lat/lngが少ないのが意外でした。けっこう使われてた記憶があるんですが、日本限定なんでしょうかね。

longは予約語に入っている言語もあるのですが、地図を一番使う環境のJavaScriptでは予約語になってないので、気にしないのが主流ということなんでしょうか。

というわけで、これからはlat/longを使おうと思います。

緯度経度と経度緯度

緯度経度を経度緯度と逆順で書く流派もあるので、ついでにその比率も調べてみました。

f:id:tanamon:20190710175936p:plain

latitude/longitude, longitude/latitude - Google トレンド

意外と拮抗していますが、やはり緯度経度の順番が多いようです。

この順番違いがバグを生むので、緯度経度の順番で統一して欲しいです。

GCEのf1-micro環境でPythonが動く環境を構築する

Google Compute Engineの無料枠のf1-micro環境でPythonの実行環境を構築した記録です。

OSはUbuntu 19.04にしました。

% gcloud compute ssh [INSTANCE_NAME]

$ cat /etc/os-release | grep VER
VERSION="19.04 (Disco Dingo)"
VERSION_ID="19.04"
VERSION_CODENAME=disco

スワップ領域が無い

アップデートや必要ライブラリを入れる前にスワップ領域を作ります。

f1-microはRAMが600MBしか無いくせに、初期状態ではスワップ領域が未設定なのです。

$ cat /proc/swaps
Filename                Type        Size    Used    Priority

そのままだとpipenv installでOutOfMemory Killerというシリアルキラーがわりと現れる世紀末環境なので、設定は必須です。

スワップ領域を作る

スワップ領域のサイズは、RAMが2GBまでの環境ではRAMの2倍が一般的らしい。

access.redhat.com

慣習に従って、1.2GBで作ります。

$ sudo dd if=/dev/zero of=/var/swapfile bs=1M count=1200
1200+0 records in
1200+0 records out
1258291200 bytes (1.3 GB, 1.2 GiB) copied, 43.4791 s, 28.9 MB/s

$ sudo chmod 600 /var/swapfile

$ sudo mkswap -L swap /var/swapfile
Setting up swapspace version 1, size = 1.2 GiB (1258287104 bytes)
LABEL=swap, UUID=1ec17506-09a4-4517-911d-c3e3e0f45428

$ sudo swapon /var/swapfile

$ cat /proc/swaps
Filename                Type        Size    Used    Priority
/var/swapfile                           file        1228796 0   -2

再起動時にスワップ領域が自動的にmountするようにする

このままだと再起動時に有効にならないので、fstabに書きます。

$ echo '/var/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab
/var/swapfile swap swap defaults 0 0

確認のため再起動してみる。

$ exit

いったんsshを終了させて、gcloudコマンドで再起動します。

% gcloud compute instances stop [INSTANCE_NAME]
% gcloud compute instances start [INSTANCE_NAME]
% gcloud compute ssh [INSTANCE_NAME]

ログインできたらマウントの確認。

$ cat /proc/swaps
Filename                Type        Size    Used    Priority
/var/swapfile                           file        1228796 0   -2

マウントされていた。

Ubuntuのアップデート

$ sudo apt update

$ sudo apt upgrade -y

anyenvのインストール

aptで入れてもいいけど、OS配布版は古いバージョンになったりするので、anyenv + pyenvを使う。

今回はPythonしか使わないのでpyenvを直接入れてもいいけど、別の言語の時でも環境構築を同一手順にしたいのでanyenvから入れる。

github.com

github.com

$ git clone https://github.com/anyenv/anyenv ~/.anyenv

$ cat << \EOS >> ~/.bashrc
if [[ -d $HOME/.anyenv ]]; then
  export PATH="$HOME/.anyenv/bin:$PATH"
  eval "$(anyenv init -)"
fi
EOS

$ exec $SHELL -l
ANYENV_DEFINITION_ROOT(/home/user/.config/anyenv/anyenv-install) doesn't exist. You can initialize it by:
> anyenv install --init

$ anyenv install --init
Manifest directory doesn't exist: /home/user/.config/anyenv/anyenv-install
Do you want to checkout ? [y/N]: y
...
Completed!

$ anyenv --version
anyenv 1.1.1

pyenvのインストール

依存ライブラリを入れる。

公式サイトによると、以下のライブラリが必要らしい。

$ sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev
xz-utils tk-dev libffi-dev liblzma-dev python-openssl git

ログを見るとbuild-essential, make, wget, curlはすでにあった。gitもすでに使ってるのである。

Minimal版を想定したライブラリ構成だろうか。

$ anyenv install pyenv

$ exec $SHELL -l

$ pyenv --version
pyenv 1.2.12-4-g525dac36

Pythonのインストール

現在の最新版3.7.3を入れる。

$ pyenv install 3.7.3

$ pyenv global 3.7.3

$ python --version
Python 3.7.3

Pipenvのインストール

pipenvの作業ディレクトリはプロジェクト配下のほうが好きなのでPIPENV_VENV_IN_PROJECTの設定をしておく。

$ pip install pipenv
...
You are using pip version 19.0.3, however version 19.1.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

$ pip install --upgrade pip

$ echo "export PIPENV_VENV_IN_PROJECT=true" >> ~/.bashrc

$ pipenv --version
pipenv, version 2018.11.26

pipが古いと言われたので、ついでに更新した。

(参考)aptでPythonを入れる場合

もし、aptで直接入れたい場合は、以下の手順で入れられる。

$ sudo apt install -y python3 python3-pip python3-venv

$ pip3 install pipenv

$ echo "export PIPENV_VENV_IN_PROJECT=true" >> ~/.bashrc

住所.jpのMySQLデータがインポートできない件

住所情報のデータベースを探したら住所.jpというのを見つけた。

jusyo.jp

お知らせが2010年からあるので、けっこう昔からデータ提供しているらしい。

しかし、試しに使ってみようと思ったらインポートエラー。

$ mysql -u root -p sandbox -p < zenkoku.sql
Enter password:
ERROR 1366 (HY000) at line 3: Incorrect integer value: '' for column 'new_id' at row 1

ファイル2行目にあるcreate tableの中で以下の部分が間違っていた。

`new_id` int(11) default NULL

型がintなのにinsert文では空文字を入れてる。

このnew_idというカラムは、

住所が廃止された場合(7)delete_flgを[ 1 ]とし、移行先の(1)idが判明していればこの項目に記載します。(現在未使用です)

住所データSQL - 仕様【住所.jp】

ドキュメントに未使用とあるので、手っ取り早く文字列型にしておく。

`new_id` varchar(11) default NULL

これでインポートできます。

pyenvにAnaconda系バージョンを入れるとPipenvの初期化に失敗する

LegacyVersion('anaconda3-5.3.1')というエラー

% pipenv --three
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/models/pyenv.py", line 53, in get_versions
    version = PythonVersion.parse(p.name)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/models/python.py", line 119, in parse
    raise ValueError("Not a valid python version: %r" % version)
ValueError: Not a valid python version: <LegacyVersion('anaconda3-5.3.1')>
...

こんなエラーが出た。LegacyVersion('anaconda3-5.3.1')らしい。

Anaconda installer archiveによると2018-11-19リリース版。なのにレガシー。

そもそもAnacondaは使ってない

% python --version
3.7.3

% which python
/Users/user/.anyenv/envs/pyenv/shims/python

デフォルトは現在最新の3.7.3を有効にしている。anacondaは使ってない。

このanaconda、どこから来たのか。

複数環境をスイッチさせてる中にanacondaを入れるとよくないという話を聞くが、こういうことが起こるからだろうか。

アナコンダは気質に悪評があり、さらにオオアナコンダは大きすぎるので、ボアと比べるとペットとしては人気がない。

アナコンダ - Wikipedia

ペットでもアナコンダは人気無いようですし(関係ない)。

pipenv --python `which python`で動く?

手探りしてたら、pipenvの初期化でパスが通ったpythonのバージョンを指定したら通った。

% pipenv --python `which python`
Creating a virtualenv for this project…
Pipfile: /Users/user/Documents/workspace/sandobox/Pipfile
Using /Users/user/.anyenv/envs/pyenv/shims/python (3.7.0) to create virtualenv…
⠏Running virtualenv with interpreter /Users/user/.anyenv/envs/pyenv/shims/python
Using base prefix '/Users/user/.anyenv/envs/pyenv/versions/anaconda3-5.3.1'
/usr/local/lib/python3.7/site-packages/virtualenv.py:1041: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
New python executable in /Users/user/Documents/workspace/sandobox/.venv/bin/python
Installing setuptools, pip, wheel...done.

Virtualenv location: /Users/user/Documents/workspace/sandobox/.venv
Creating a Pipfile for this project…

この指定で動くのも、また謎すぎる。

Using base prefix '/Users/user/.anyenv/envs/pyenv/versions/anaconda3-5.3.1'というログが残ってるから、強引に置き換えて無理やり動かした感じがする。

やっぱり動かない

% pipenv shell
Warning: Your Pipfile requires python_version 3.7, but you are using None (/Users/user/D/w/s/.venv/bin/python).
  $ pipenv --rm and rebuilding the virtual environment may resolve the issue.
  $ pipenv check will surely fail.
Launching subshell in virtual environment…
 . /Users/user/Documents/workspace/sandbox/.venv/bin/activate
%  . /Users/user/Documents/workspace/sandbox/.venv/bin/activate

pipenv shellをすると警告が出た。いちおう、shellには入れる。

(sandbox) % pipenv install requests
Warning: Your Pipfile requires python_version 3.7, but you are using None (/Users/user/D/w/s/.venv/bin/python).
  $ pipenv --rm and rebuilding the virtual environment may resolve the issue.
  $ pipenv check will surely fail.
Installing requests…
⠋
Error:  An error occurred while installing requests!
/bin/sh: /Users/user/Documents/workspace/sandbox/.venv/bin/pip: /Users/user/Documents/workspace/proxy/.venv/bin/python: bad interpreter: No such file or directory

installが使えないので、やはり正常にインストールされてなかった。

Anacondaを消してみる

Anacondaを消して、再度pipenvしてみる。

% pyenv uninstall anaconda anaconda3-5.3.1
pyenv: remove /Users/user/.anyenv/envs/pyenv/versions/anaconda3-5.3.1? y

% pyenv versions
  system
* 3.7.3 (set by /Users/user/.anyenv/envs/pyenv/version)

% rm .venv

% pipenv --three
Creating a virtualenv for this project…
Pipfile: /Users/user/Documents/workspace/sandbox/Pipfile
Using /Users/user/.anyenv/envs/pyenv/shims/python3 (3.7.3) to create virtualenv…
⠧Running virtualenv with interpreter /Users/user/.anyenv/envs/pyenv/shims/python3
Using base prefix '/Users/user/.anyenv/envs/pyenv/versions/3.7.3'
/usr/local/lib/python3.7/site-packages/virtualenv.py:1041: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
New python executable in /Users/user/Documents/workspace/sandbox/.venv/bin/python3
Also creating executable in /Users/user/Documents/workspace/sandbox/.venv/bin/python
Installing setuptools, pip, wheel...done.

Virtualenv location: /Users/user/Documents/workspace/sandbox/.venv

動いた。

Anacondaが最新だったら

Anacondaが古いからダメなのかもしれないと思い、最新のAnacondaを入れて、再度pipenvをしてみる。

% pyenv install anaconda3-2019.03
Downloading Anaconda3-2019.03-MacOSX-x86_64.sh...
-> https://repo.continuum.io/archive/Anaconda3-2019.03-MacOSX-x86_64.sh
Installing Anaconda3-2019.03-MacOSX-x86_64...
Installed Anaconda3-2019.03-MacOSX-x86_64 to /Users/user/.anyenv/envs/pyenv/versions/anaconda3-2019.03

% pyenv versions
  system
* 3.7.3 (set by /Users/user/.anyenv/envs/pyenv/version)
  anaconda3-2019.03

% pipenv --three
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/models/pyenv.py", line 53, in get_versions
    version = PythonVersion.parse(p.name)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/models/python.py", line 119, in parse
    raise ValueError("Not a valid python version: %r" % version)
ValueError: Not a valid python version: <LegacyVersion('anaconda3-2019.03')>
...

やはりエラーになる。LegacyVersionって、それ現在の最新版ですよ!

どうやらpyenvにAnacondaを混ぜるとよくないらしい。

ビルドインのpipenvを使わなければ動く

pyenvで入れたPythonにPipenvをインストールすれば動く。

% which pipenv
/usr/local/bin/pipenv

% pip install pipenv
...

% which pipenv
/Users/user/.anyenv/envs/pyenv/shims/pipenv

% pipenv --three
Creating a virtualenv for this project…
Pipfile: /Users/user/Documents/workspace/sandbox/Pipfile
Using /Users/user/.anyenv/envs/pyenv/versions/3.7.3/bin/python3 (3.7.3) to create virtualenv…
⠧ Creating virtual environment...Already using interpreter /Users/user/.anyenv/envs/pyenv/versions/3.7.3/bin/python3
Using base prefix '/Users/user/.anyenv/envs/pyenv/versions/3.7.3'
New python executable in /Users/user/Documents/workspace/sandbox/.venv/bin/python3
Also creating executable in /Users/user/Documents/workspace/sandbox/.venv/bin/python
Installing setuptools, pip, wheel...
done.
Running virtualenv with interpreter /Users/user/.anyenv/envs/pyenv/versions/3.7.3/bin/python3

✔ Successfully created virtual environment!
Virtualenv location: /Users/user/Documents/workspace/sandbox/.venv

今までPipenvはMacのビルドイン版を使ってたけど、こっちのほうがいいのかな。

エラーログ(検索用)

% pipenv --three
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/models/pyenv.py", line 53, in get_versions
    version = PythonVersion.parse(p.name)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/models/python.py", line 119, in parse
    raise ValueError("Not a valid python version: %r" % version)
ValueError: Not a valid python version: <LegacyVersion('anaconda3-5.3.1')>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/bin/pipenv", line 11, in <module>
    sys.exit(cli())
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/click/core.py", line 1114, in invoke
    return Command.invoke(self, ctx)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/click/decorators.py", line 64, in new_func
    return ctx.invoke(f, obj, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/click/decorators.py", line 17, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/pipenv/cli/command.py", line 203, in cli
    clear=state.clear,
  File "/usr/local/lib/python3.7/site-packages/pipenv/core.py", line 565, in ensure_project
    pypi_mirror=pypi_mirror,
  File "/usr/local/lib/python3.7/site-packages/pipenv/core.py", line 488, in ensure_virtualenv
    python = ensure_python(three=three, python=python)
  File "/usr/local/lib/python3.7/site-packages/pipenv/core.py", line 401, in ensure_python
    path_to_python = find_a_system_python(python)
  File "/usr/local/lib/python3.7/site-packages/pipenv/core.py", line 364, in find_a_system_python
    python_entry = finder.find_python_version(line)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/pythonfinder.py", line 90, in find_python_version
    return self.system_path.find_python_version(
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/pythonfinder.py", line 44, in system_path
    ignore_unsupported=self.ignore_unsupported,
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/models/path.py", line 309, in create
    ignore_unsupported=ignore_unsupported,
  File "<attrs generated init 21cfbcaf749d3af30eb10d5110d156423170deac>", line 37, in __init__
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/models/path.py", line 102, in __attrs_post_init__
    self._setup_pyenv()
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/models/path.py", line 133, in _setup_pyenv
    self.pyenv_finder = PyenvFinder.create(root=PYENV_ROOT, ignore_unsupported=self.ignore_unsupported)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/models/pyenv.py", line 98, in create
    return cls(root=root, ignore_unsupported=ignore_unsupported)
  File "<attrs generated init e2de76c84a062f4c9c55ad2f5f11c1f2c8b33679>", line 7, in __init__
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/models/pyenv.py", line 57, in get_versions
    version = self.version_from_bin_dir(bin_dir)
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/models/pyenv.py", line 36, in version_from_bin_dir
    version = get_python_version(py.as_posix())
  File "/usr/local/lib/python3.7/site-packages/pipenv/vendor/pythonfinder/utils.py", line 41, in get_python_version
    raise InvalidPythonVersion("%s is not a valid python path" % path)
pipenv.vendor.pythonfinder.exceptions.InvalidPythonVersion: /Users/user/.anyenv/envs/pyenv/versions/anaconda3-5.3.1/bin/anaconda is not a valid python path

MySQL5.6以降では時刻系の型に精度未満の値を入れると四捨五入される

昔の記憶のまま使ってたらハマった話。

先に検証用のテーブルを作る。

time, datetime, timestampそれぞれの型で、デフォルト精度(カッコなし)とマイクロ秒精度(6指定)のカラムを加えておきます。

mysql> set sql_mode = '';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> create table test(
    ->   id int unsigned not null auto_increment,
    ->   test_time time,
    ->   test_datetime datetime,
    ->   test_timestamp timestamp,
    ->   test_time_full time(6),
    ->   test_datetime_full datetime(6),
    ->   test_timestamp_full timestamp(6),
    ->   primary key (id)
    -> );
Query OK, 0 rows affected (0.04 sec)

set sql_mode='';は試したCloudSQL環境でエラーになったので足していますが、他の環境では不要かも。

このテーブルにデータを入れて確認してみます。

mysql> insert into test (
    ->     test_time, test_datetime, test_timestamp,
    ->     test_time_full, test_datetime_full, test_timestamp_full
    -> )
    -> values (
    ->     '23:59:59.999999', '2019/12/31 23:59:59.999999', '2019/12/31 23:59:59.999999',
    ->     '23:59:59.999999', '2019/12/31 23:59:59.999999', '2019/12/31 23:59:59.999999'
    -> );
Query OK, 1 row affected (0.02 sec)
mysql> select * from test \G
*************************** 1. row ***************************
                 id: 1
          test_time: 24:00:00
      test_datetime: 2020-01-01 00:00:00
     test_timestamp: 2020-01-01 00:00:00
     test_time_full: 23:59:59.999999
 test_datetime_full: 2019-12-31 23:59:59.999999
test_timestamp_full: 2019-12-31 23:59:59.999999
1 row in set (0.00 sec)

結果は23:59:59となる(秒未満は切り捨てられる)と思っていましたが、そうではなく繰り上げられて24:00:00になっています。 さらに日付付きだと翌年になっています。

これは予想外。なぜだろうか。

MySQLはたまにしか使わないけど、昔の記憶を辿ってもこんな処理にはなってなかったと思う。

検索するとMySQL5.5と5.6で挙動が変わると書いてあった。

公式ドキュメントも確認します。

MySQL 5.6.4 より前では、時間値で小数秒部分が許可されているインスタンスは制限されています。 (略) ただし、MySQL は時間データ型のカラムに値を格納するときに、小数部を破棄し、それを格納しません。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 11.3.6 時間値での小数秒

MySQL 5.6.3までは、破棄、つまり切り捨てが行われるようです。

MySQL 5.6.4 以降では、マイクロ秒 (6 桁) までの精度を持つ TIME、DATETIME、および TIMESTAMP 値に対して小数秒のサポートを拡張しています。

小数秒部分を持つ TIME、DATE、または TIMESTAMP 値を同じ型のカラムに挿入するが、小数部の桁数が少ない場合、次の例に示すように丸めが行われます。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 11.3.6 時間値での小数秒

MySQL 5.6.4以降は、丸め、つまり四捨五入が行われるようです。

MySQL 5.6系のGeneral Availability(正式)版は5.6.10からなので、実質的に5.5系は切り捨て、5.6系は四捨五入という理解で良さそうです。

さらに、

0 の値は、小数部がないことを表します。省略した場合、デフォルトの精度は 0 です。(これは、以前の MySQL バージョンと互換性を保つため、標準 SQL のデフォルトである 6 とは異なっています。)

MySQL :: MySQL 5.6 リファレンスマニュアル :: 12.20.4 丸め動作

という記述もありました。

標準とは異なると書いてある。なるほど、地雷を踏み抜いてたわ。

トラブルが起きたコード

もともと、精度指定をしないtimestamp型にある期間の終了日時を入れるテーブルがあった。

Python実装だったので以下のようなコード。

>>> import arrow
>>> arrow.get().ceil('day').datetime
datetime.datetime(2019, 7, 4, 23, 59, 59, 999999, tzinfo=tzutc())

終了時間を雑にceilで上げたものをSQLで入れたら、翌日00:00:00にされていた。

で、別の場所では日にちだけの精度でwhereで絞ってたので翌日のデータが混じるというのが起きたトラブルでした。

データの修正

テーブル定義を直したら、すでに入ってる間違ったデータもなんとかしたい。

mysql> select addtime('2020-01-01 00:00:00', '-.000001');
+--------------------------------------------+
| addtime('2020-01-01 00:00:00', '-.000001') |
+--------------------------------------------+
| 2019-12-31 23:59:59.999999                 |
+--------------------------------------------+
1 row in set (0.02 sec)

addtimeで-1マイクロ秒を足してあげればよい。

一括で更新する場合には、whereにmicrosecond()を使うと、ずれたデータだけ指定できる。今回の場合では= 0で比較しておけばよい。

mysql> select microsecond('2020-01-01 00:00:00');
+------------------------------------+
| microsecond('2020-01-01 00:00:00') |
+------------------------------------+
|                                  0 |
+------------------------------------+
1 row in set (0.00 sec)

mysql> select microsecond('2019-12-31 23:59:59.999999');
+-------------------------------------------+
| microsecond('2019-12-31 23:59:59.999999') |
+-------------------------------------------+
|                                    999999 |
+-------------------------------------------+
1 row in set (0.00 sec)

CloudSQLでcreate tableが失敗する理由

ERROR 1067 (42000): Invalid default value for 'test_timestamp_full'

このエラーが出ます。

原因はsql_modeにNO_ZERO_DATEが指定されているせいです。

MySQL 5.6.17以降ではNO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZEROは非推奨になっています。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 5.1.7 サーバー SQL モード

ですが、Cloud SQLは5.6.17以降でもこれらが有効になっているようです。

mysql> select version();
+-------------------+
| version()         |
+-------------------+
| 5.7.14-google-log |
+-------------------+
1 row in set (0.04 sec)
mysql> SELECT @@GLOBAL.sql_mode;
+-------------------------------------------------------------------------------------------------------------------------------------------+
| @@GLOBAL.sql_mode                                                                                                                         |
+-------------------------------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+-------------------------------------------------------------------------------------------------------------------------------------------+

さらに、timestampが2つ以上あって、両方ともdefault nullの場合に失敗します。

なので、以下のSQLのようにdefault値を設定すればエラーが解消されます。

mysql> create table test(
    ->   id int unsigned not null auto_increment,
    ->   test_time time,
    ->   test_datetime datetime,
    ->   test_timestamp timestamp,
    ->   test_time_full time(6),
    ->   test_datetime_full datetime(6),
    ->   test_timestamp_full timestamp(6) default current_timestamp(6),
    ->   primary key (id)
    -> );
Query OK, 0 rows affected (0.03 sec)

しかし、以下のSQLは失敗します。

mysql> create table test(
    ->   id int unsigned not null auto_increment,
    ->   test_time time,
    ->   test_datetime datetime,
    ->   test_timestamp timestamp default current_timestamp,
    ->   test_time_full time(6),
    ->   test_datetime_full datetime(6),
    ->   test_timestamp_full timestamp(6),
    ->   primary key (id)
    -> );
ERROR 1067 (42000): Invalid default value for 'test_timestamp_full'

この理由はよくわからない。