ラベル JavaScript の投稿を表示しています。 すべての投稿を表示
ラベル JavaScript の投稿を表示しています。 すべての投稿を表示

2021年8月11日水曜日

【正規表現】連続する同一文字を含む文字列かどうかを判断する。【JavaScript】


var continueChar = function( str ) {
  const regexp = /(.)\1{3,}/;   // 4つ連続で同一文字を含む
  return regexp.test( str );
};

exports.continueChar = continueChar;

2021年5月30日日曜日

【JavaScript】Day.jsでの日付妥当性をisValid()で。

Day.jsで日付の妥当性は isValid() を使うとできます。しかし、検索をすると使えない(日付の検証には使えない。)と結果が出てきます。それは誤りで、plugin を利用すれば可能です。customParseFormat を追加しましょう。

ポイント

  • プラグイン customParseFormat を追加。
  • dayjs() の第3引数 strict に true を指定。
const dayjs = require('dayjs');

// プラグイン 追加
const customParseFormat = require('dayjs/plugin/customParseFormat');
dayjs.extend(customParseFormat);

console.log( dayjs( '20210102', 'YYYYMMDD' ).isValid() ); // => true
console.log( dayjs( '20210132', 'YYYYMMDD' ).isValid() ); // => true
console.log( dayjs( '20210102', 'YYYYMMDD', true ).isValid() ); // => true
console.log( dayjs( '20210132', 'YYYYMMDD', true ).isValid() ); // => false
console.log( dayjs( '2021013a', 'YYYYMMDD', true ).isValid() ); // => false

【JavaScript】Day.jsのAPIサンプル(Parse編)

 Day.jsの使い方を知るためにサンプルを作っています。

Parse

 日付や時刻を含む文字列や数値からオブジェクトを作成するものです。作成されたオブジェクトはUTC時間だったりするので、利用時は気を付けないと想定とずれた時間になります。

Parse

 テキストをオブジェクトに変換します。日本語の日付を使うなどする場合など、「Invalid Date」でエラーとなってしまうときは、CustomParseFormat プラグインを利用することも頭に入れておくとよいです。

const dayjs = require('dayjs');

// JST:2021-04-30 00:00:00
// UTC:2021-04-29 15:00:00 (日本との差は-9時間のため)
console.log( dayjs('2021-04-30', 'YYYY-MM-DD').toDate() );
// => 2021-04-29T15:00:00.000Z (UTC)
console.log( dayjs('2021年04月30日', 'YYYY年MM月DD日').toDate() );
// => Invalid Date (日本語があるとパースできない.)

// プラグインを追加 
const CustomParseFormat = require('dayjs/plugin/customParseFormat');
dayjs.extend(CustomParseFormat);

console.log( dayjs('2021年04月30日', 'YYYY年MM月DD日').toDate() );
// => 2021-04-29T15:00:00.000Z (日本語があってもパースできる.)
console.log( dayjs('2021年04月30日', 'YYYY年MM月DD日').locale('ja').format() );
// => 2021-04-30T00:00:00+09:00 (日本でロケールしてみただけ.)

Now

 現在時刻のオブジェクト取得します。日本時間にするには ロケール変換+format() します。

const dayjs = require('dayjs');

let now_utc = dayjs();
let now_jst = dayjs().locale('ja');
console.log( now_utc.toDate() );
// => 2021-04-30T00:09:31.085Z (こちらは0時)
console.log( now_jst.format() );
// => 2021-04-30T09:09:31+09:00 (こちらは9時. toDate() はUTCになってしまうので注意.)

String

 ISO 8601形式の文字列からオブジェクトを作成します。日付と時刻の間に"T"を付け、時刻の後ろに"Z"や"+0900"などを付与した文字列です。

const dayjs = require('dayjs');

let utc = dayjs('2021-04-15T15:00:00.000Z');
console.log( utc.toDate() );

let jst = dayjs('2021-04-15T15:00:00.000+0900');
console.log( jst.locale('ja').format() ); // toDate()はUTC時間で出力される

String + Format

 事前に日付のフォーマットわかっていれば、引数の日付の文字列からオブジェクトが作成できます。注意すべきは CustomParseFormat プラグインを使わなければいけないことです。補足ですが、dayjs()の第4引数に真偽を指定すると、結果が変わります。

const dayjs = require('dayjs');
// プラグイン
const customParseFormat = require('dayjs/plugin/customParseFormat');

dayjs.extend(customParseFormat); // プラグイン追加
let jst = dayjs('2021年10月18日', 'YYYY年MM月DD日', 'ja');
console.log(jst.locale('ja').format());

let jst_imp = dayjs('2021年10月32日', 'YYYY年MM月DD日', 'ja');
let jst_strict = dayjs('2021年10月32日', 'YYYY年MM月DD日', 'ja', true);

console.log(jst_imp.locale('ja').format());
// => 2021-11-01T00:00:00+09:00  第4引数がtrueでない場合、日付の繰り越しが起こる.
console.log(jst_strict.locale('ja').format());
// => Invalid Date 第4引数がtrueの場合、日付の厳密性がチェックされ、存在しない日付の場合、
エラー(Invalid Date)になる.

 日付のフォーマットが1つではなく複数指定される可能性がある場合でもオブジェクト作成できます。日付のフォーマットを配列で指定してあげます。

const dayjs = require('dayjs');
const customParseFormat = require('dayjs/plugin/customParseFormat');

dayjs.extend(customParseFormat);
let date  = dayjs("2001-12-25", ["YYYY", "YYYY-MM-DD"], 'ja', true);
let date2 = dayjs("2001", ["YYYY", "YYYY-MM-DD"], 'ja', true);
console.log(date.locale('ja').format());  // => 2001-12-25T00:00:00+09:00
console.log(date2.locale('ja').format()); // => 2001-01-01T00:00:00+09:00


let date3 = dayjs("2001-25-12", ["YYYY", "YYYY-MM-DD"], 'ja', true);
let date4 = dayjs("2001-25-12", ["YYYY", "YYYY-MM-DD"], 'ja');
console.log(date3.locale('ja').format());  // => Invalid Date
console.log(date4.locale('ja').format());  // => 2001-01-01T00:00:00+09:00

Unix Timestamp (milliseconds)

 ミリ秒を表す数値を指定することでオブジェクトを作成します。基準日は1970年1月1日午前0時です。引数に指定したミリ秒だけ加算された日時のオブジェクトが作成されます。

const dayjs = require('dayjs');

let date = dayjs(0);
console.log( date.toDate() );
// => 1970-01-01T00:00:00.000Z

let date1 = dayjs(1);
console.log( date1.toDate() );
// => 1970-01-01T00:00:00.001Z

Unix Timestamp (seconds)

 秒を表す数値を指定し、オブジェクトを作成します。基準日は1970年1月1日午前0時です。引数に指定した秒だけ加算された日時のオブジェクトが作成されます。

const dayjs = require('dayjs');

let date = dayjs.unix(0);
console.log( date.toDate() );
// => 1970-01-01T00:00:00.000Z

let date2 = dayjs.unix(1);
console.log( date2.toDate() );
// => 1970-01-01T00:00:01.000Z dayjs()をラップしている.

let date3 = dayjs( 1 * 1000 );
console.log( date3.toDate() );
// => 1970-01-01T00:00:01.000Z 

Date

 JavaScriptのDateオブジェクトからオブジェクトを作成します。Dateオブジェクトのクローンを返すため、元のDateオブジェクトを変更しても、Day.jsオブジェクトは変更されません。その逆も同様です。

const dayjs = require('dayjs');

var d = new Date(2019, 7, 18); // monthは0-11を指定し、1月-12月を扱う罠.
var day = dayjs(d);

console.log( d );  // => 2019-08-17T15:00:00.000Z
console.log( day.toDate() );  // => 2019-08-17T15:00:00.000

Object

 オブジェクトからDay.jsオブジェクトを作成します。ObjectSupport プラグインを追加して使用します。

const dayjs = require('dayjs');
const ObjectSupport = require('dayjs/plugin/objectSupport'); // プラグイン

// プラグイン追加.
dayjs.extend(ObjectSupport);

let now = dayjs();
let date = dayjs({ hour:15, minute:10 });
console.log( now.toDate() );
// => 2021-05-01T07:51:36.994Z
console.log( date.toDate() );
// => 2021-05-01T06:10:00.000Z
// 当日の日本時間15時10分を指す?。UTCにすると9時間前なので、6時10分となる。

now = dayjs();
let date2 = dayjs({});  // 空のオブジェクトは現在日時
console.log( now.toDate() );
// => 2021-05-01T07:54:59.148Z
console.log( date2.toDate() );
// => 2021-05-01T07:54:59.148Z

let date3 = dayjs({ year :2010, month :3, day :5, hour :15, minute :10, second :3, millisecond :123});
console.log( date3.toDate() );
// => 2010-04-05T06:10:03.123Z
// monthは0-11の整数で、1月-12月を表す.

Array

 配列からDay.jsオブジェクトを作成します。arraySupport プラグインを追加する必要があります。dayjs([]) は現在時刻です。

const dayjs = require('dayjs');
const ArraySupport = require('dayjs/plugin/arraySupport');

dayjs.extend(ArraySupport);

// [ 年、月、日、時、分、秒、ミリ秒 ]
let date = dayjs([2010, 1, 14, 15, 25, 50, 125]);
console.log( date.toDate() );
// => 2010-02-14T06:25:50.125Z
// month部分は0-11を指定することで、1月-12月を表します。
// ログ出力ではUTC時間になるため、時刻が9時間前となります。 

let date2 = dayjs([2010, 6]);     // July 1st
console.log( date2.toDate() );
// => 2010-06-30T15:00:00.000Z
// month:6 は7月のこと。7/1 00:00:00から-9時間となり、6/30 15:00:00となる。 
// UTC時間は面倒だ。

UTC

 UTC時間のDay.jsオブジェクトを作成します。

const dayjs = require('dayjs');
const utc = require('dayjs/plugin/utc');

dayjs.extend(utc);

let date = dayjs();
console.log( date.format() );
// => 2021-05-02T09:10:25+09:00
// 日本で実行しているので、format()は日本時間が出力される。
let date_utc = dayjs().utc();
console.log( date_utc.format() );
// => 2021-05-02T00:10:25Z
// 日本で実行していても、format()はUTC時間で出力される。 

Dayjs Clone

 Day.jsオブジェクトを複製して、同じオブジェクトを作成します。2種類の方法があり、複製元からclone()を使うか、dayjs()の引数に複製元を渡すかです。

const dayjs = require('dayjs');

let a = dayjs();
let b = a.clone();

console.log( a.toDate() ); // => 2021-05-02T00:18:31.274Z
console.log( b.toDate() ); // => 2021-05-02T00:18:31.274Z

a = dayjs();
b = dayjs(a);

console.log( a.toDate() ); // => 2021-05-02T00:18:31.325Z
console.log( b.toDate() ); // => 2021-05-02T00:18:31.325Z

Validation

 日付が正しいかチェックします。customParseFormat プラグインを使用します。注意しなければならないのは、dayjs()の第3引数の真偽です。厳密に日付の正しさを求めるならば true を指定します。そうでない場合、日付が正しくない場合でも繰り上げなどの計算をしてくれます。

const dayjs = require('dayjs');
// プラグイン
const customParseFormat = require('dayjs/plugin/customParseFormat');

// プラグインを追加 
dayjs.extend(customParseFormat);

let date = dayjs('2021-03-19', 'YYYY-MM-DD', true);
console.log( date.isValid() ); // => true

let date2 = dayjs('2021-15-19', 'YYYY-MM-DD', true);
console.log( date2.isValid() ); // => false

// 日付の形式が合っていればOKのやりかた。
let date3 = dayjs('2021-13-19', 'YYYY-MM-DD');
console.log( date4.isValid() ); // => true. 日付の形式が合っていればOKとなる。
console.log( date3.toDate() );
// => 2022-01-18T15:00:00.000Z
// 日付を勝手に繰り上げする.

【JavaScript】MS932で文字を判断する。

JavaScriptを使って、MS932文字コードで文字を判断します。ライブラリは iconv-lite を利用。


const iconv = require('iconv-lite');

let buf = iconv.encode('亜', 'ms932' );
console.log( buf );  //=> <Buffer 88 9f>  [0x88, 0x9f]の意味。

// MS932の亜に対応した数値。8ビットシフトするのがポイント。
let enc = buf[0] << 8 + buf[1];  // 0x889f 
if ( enc === 0x889f ){
  console.log('亜だね。');
}

【JavaScript】Day.jsで年齢計算をする。

 基準日時点で生年月日から年齢はいくつかを計算します。


  let base = dayjs(baseDate, YYYYMMDD, true);  // 基準日
  let birth = dayjs(birthday, YYYYMMDD, true); // 生年月日 


  let ibase = Number( base.format(YYYYMMDD) );
  let ibirth = Number( birth.format(YYYYMMDD) );

  return Math.floor( (ibase - ibirth)/10000 );

【JavaScript】Day.jsで日付演算処理を行う。

 元となるソースはGitHub上にあります。

共通

 共通的に必要となる定義を示します。フォーマット変換するので、プラグインを入れるのがポイントです。


const dayjs = require("dayjs");
// プラグインの追加
dayjs.extend(require("dayjs/plugin/customParseFormat"));

// フォーマット
const YYYYMMDD = "YYYYMMDD";
const YYYYMMDD_HHmmss = "YYYYMMDD HHmmss";
const YYYYMMDD_HHmmss_SSS = "YYYYMMDD HHmmss.SSS";

エラー判定処理

 Day.jsの癖として、日付処理ができない場合は「Invalid Date」という文字列を返します(細かいことはわかりませんが。)。それを利用したエラー判定を行います。これは下で示していく自作APIが処理エラー時にnullを返したいために作られました。


function isValidDate(day) {
  if (typeof day === "string") {
    return day === "Invalid Date" ? null : day;
  }

  return day.isValid() ? day : null;
}

年齢計算

 diff()のポイントは、基準日に対し過去が正の値・未来が負の値となることです。つまり基準日.diff(過去日) > 0 で、基準日.diff(未来日) < 0 です。


/**
 * 年齢計算
 * @param {string} baseDate  年齢計算の基準日 YYYYMMDD
 * @param {string} birthday  生年月日 YYYYMMDD
 * @returns 満年齢 or null(計算不可).誕生日に年をとる.
 */
exports.calcAge = (baseDate, birthday) => {
  let base = dayjs(baseDate, YYYYMMDD, true);
  let birth = dayjs(birthday, YYYYMMDD, true);

  // 日付をパースできない.
  if (!isValidDate(base) || !isValidDate(birth)) {
    return null;
  }

  let ibase = Number( base.format(YYYYMMDD) );
  let ibirth = Number( birth.format(YYYYMMDD) );

  return Math.floor( (ibase - ibirth)/10000 );
};

日付計算(年)

 日付計算において、年・月・日の加減算はadd()の引数に"year"、"month"、"day"を指定することで計算を行う。

/**
 * 日付計算(年)
 * @param {string} baseDate 基準日 YYYYMMDD
 * @param {number} year 加減算する年
 * @returns {string|null} 加減算後の日付 YYYYMMDD
 */
exports.addYears = (baseDate, year) => {
  return isValidDate(
    dayjs(baseDate, YYYYMMDD, true).add(year, "year").format(YYYYMMDD)
  );
};

日付計算(月)

/**
 * 日付計算(月)
 * @param {string} baseDate 基準日 YYYYMMDD
 * @param {number} month 加減算する月
 * @returns {string|null} 加減算後の日付 YYYYMMDD
 */
exports.addMonths = (baseDate, month) => {
  return isValidDate(
    dayjs(baseDate, YYYYMMDD, true).add(month, "month").format(YYYYMMDD)
  );
};

日付計算(日)

/**
 * 日付計算(日)
 * @param {string} baseDate 基準日 YYYYMMDD
 * @param {number} day 加減算する日
 * @returns {string|null} 加減算後の日付 YYYYMMDD
 */
exports.addDays = (baseDate, day) => {
  return isValidDate(
    dayjs(baseDate, YYYYMMDD, true).add(day, "day").format(YYYYMMDD)
  );
};

日付フォーマッター

/**
 * 日付フォーマット
 * @param {string} baseDate 日付日時
 * @param {string} format フォーマット. フォーマット形式はDay.js参照.
 * @returns {string|null} フォーマット後日付
 */
exports.format = (baseDate, format) => {
  return isValidDate(dayjs(baseDate).format(format));
};

月末算出

 ライブラリが優秀なので、うるう年も対応しています。


/**
 * 月末の日付を返す.
 * @param {string} baseDate 日付 YYYYMMDD or YYYYMM
 * @returns {string|null} 月末日付 YYYYMMDD
 */
exports.endOfMonth = (baseDate) => {
  return isValidDate(
    dayjs(baseDate, [YYYYMMDD, "YYYYMM"], true).endOf("month").format(YYYYMMDD)
  );
};

日付比較

 isBefore()は基準日と比較して比較対象日付が未来ならばtrue、過去ならばfalseとなります。つまり、基準日.isBefore(過去日 "day") はtrue、基準日.isBefore(未来日, "day")はfalseです。

/**
 * 日付比較
 * @param {string} baseDate 基準日 YYYYMMDD
 * @param {string} compDate 対象日 YYYYMMDD
 * @returns {number|null} 比較結果. 基準日 < 対象日 は -1, 基準日 = 対象日 は 0, 基準日 > 対象日 は 1
 */
exports.compare = (baseDate, compDate) => {
  const base = dayjs(baseDate, YYYYMMDD, true);
  const comp = dayjs(compDate, YYYYMMDD, true);

  if (!isValidDate(base) || !isValidDate(comp)) {
    return null;
  }

  if (base.isSame(comp, "days")) {
    return 0;
  }

  return base.isBefore(comp, "days") ? -1 : 1;
};

日付差分日数

 やっていることは年齢計算と同じで、年を計算するか日数を計算するかの違いです。

/**
 * 差分日数
 * @param {string} fromDate 基準日 YYYYMMDD
 * @param {string} toDate 対象日 YYYYMMDD
 * @returns {number|null} 計算結果. 基準日 < 対象日は 正の値、基準日 > 対象日は 負の値.
 */
exports.diffDays = (fromDate, toDate) => {
  let from = dayjs(fromDate, YYYYMMDD, true);
  let to = dayjs(toDate, YYYYMMDD, true);

  if (!isValidDate(from) || !isValidDate(to)) {
    return null;
  }

  return to.diff(from, "day");
};

エポック <-> UTC時間変換

 UTC時間を使う場合、プラグインを追加します。またエポック時間には秒とミリ秒で使い方が違うので注意します。

エポック秒 to UTC時間

/**
 * エポック(秒) to UTC変換
 * @param {number} seconds Unixエポック
 * @returns {string|null} UTC時間 YYYYMMDD hhmmss
 */
exports.epocSecToUtc = (seconds) => {
  dayjs.extend(require("dayjs/plugin/utc"));  // 本来はファイルの先頭で宣言
  return isValidDate(dayjs.unix(seconds).utc().format(YYYYMMDD_HHmmss));
};

エポックミリ秒 to UTC変換

/**
 * エポック(ミリ秒) to UTC変換
 * @param {number} miliseconds
 * @returns {string|null} UTC時間 YYYYMMDD hhmmss.SSS
 */
exports.epocMilliSecToUtc = (miliseconds) => {
  dayjs.extend(require("dayjs/plugin/utc"));  // 本来はファイルの先頭で宣言
  return isValidDate(dayjs(miliseconds).utc().format(YYYYMMDD_HHmmss_SSS));
};

UTC to エポック秒

/**
 * UTC to エポック(秒)
 * @param {string} baseDate 日付
 * @returns {number|null} エポック(秒)
 */
exports.utcToEpocSec = (baseDate) => {
  dayjs.extend(require("dayjs/plugin/utc"));  // 本来はファイルの先頭で宣言
  let utc = dayjs.utc(baseDate);
  if (!isValidDate(utc)) {
    return null;
  }
  return utc.unix();
};

UTC to エポックミリ秒

/**
 * UTC to エポック(ミリ秒)
 * @param {string} baseDate YYYYMMDD HHmmss.SSS
 * @returns {number|null} エポック(ミリ秒)
 */
exports.utcToEpocMilliSec = (baseDate) => {
  dayjs.extend(require("dayjs/plugin/utc"));  // 本来はファイルの先頭で宣言
  let utc = dayjs.utc(baseDate);
  if (!isValidDate(utc)) {
    return null;
  }
  return utc.valueOf();
};

UTC <-> JST 変換

 Day.jsオブジェクトは実行環境のロケールに合わせてしまうので、クラウドのリージョンなどの環境では注意が必要ですが、今回は環境に依存しないように実装しています。

UTC to JST

/**
 * UTC to JST変換
 * @param {string} baseUtc UTC時間. YYYYMMDD HHmmss
 * @returns {string|null} 日本時間. YYYYMMDD HHmmss
 */
exports.utcToJst = (baseUtc) => {
  dayjs.extend(require("dayjs/plugin/timezone"));  // 本来はファイルの先頭で宣言
  dayjs.extend(require("dayjs/plugin/utc"));  // 本来はファイルの先頭で宣言
  dayjs.tz.setDefault("Asia/Tokyo");

  let utc = dayjs.utc(baseUtc, YYYYMMDD_HHmmss);
  if (!isValidDate(utc)) {
    return null;
  }

  return utc.tz().format(YYYYMMDD_HHmmss);
};

JST to UTC

/**
 * JST to UTC変換
 * @param {string} baseJst YYYYMMDD HHmmss
 * @returns {string|null} UTC. YYYYMMDD HHmmss
 */
exports.jstToUtc = (baseJst) => {
  dayjs.extend(require("dayjs/plugin/timezone"));  // 本来はファイルの先頭で宣言
  dayjs.extend(require("dayjs/plugin/utc"));  // 本来はファイルの先頭で宣言
  dayjs.tz.setDefault("Asia/Tokyo");
  let jst = dayjs(baseJst, YYYYMMDD_HHmmss, true);
  if (!isValidDate(jst)) {
    return null;
  }

  return jst.utc().format(YYYYMMDD_HHmmss);
};