summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorかっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>2026-01-08 12:16:33 +0900
committerGitHub <noreply@github.com>2026-01-08 12:16:33 +0900
commitcd973b252a1304b207893b8f2327fc861d7492db (patch)
tree5dcd7cd1761b688e5f0ea01a9d61e9276c95db1e
parentenable and fix no-unused-vars and no-async-promise-executor (#17070) (diff)
downloadmisskey-cd973b252a1304b207893b8f2327fc861d7492db.tar.gz
misskey-cd973b252a1304b207893b8f2327fc861d7492db.tar.bz2
misskey-cd973b252a1304b207893b8f2327fc861d7492db.zip
fix(frontend): 2月29日を誕生日に設定している場合、平年は3月1日を誕生日として扱うように (#17072)
* fix(frontend): 2月29日を誕生日に設定している場合、平年は3月1日を誕生日として扱うように * Update Changelog * add tests * spdx
-rw-r--r--CHANGELOG.md1
-rw-r--r--packages/frontend/src/boot/main-boot.ts9
-rw-r--r--packages/frontend/src/pages/user/home.vue15
-rw-r--r--packages/frontend/src/utility/is-birthday.ts28
-rw-r--r--packages/frontend/test/is-birthday.test.ts55
5 files changed, 92 insertions, 16 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a0a9025dbd..db90bb74b7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@
- Fix: ドライブのソートが「登録日(昇順)」の場合に正しく動作しない問題を修正
- Fix: 管理画面でアーカイブ済のお知らせを表示した際にアクティブなお知らせが多い旨の警告が出る問題を修正
- Fix: ファイルタブのセンシティブメディアを開く際に確認ダイアログを出す設定が適用されない問題を修正
+- Fix: 2月29日を誕生日に設定している場合、閏年以外は3月1日を誕生日として扱うように修正
### Server
- Enhance: OAuthのクライアント情報取得(Client Information Discovery)において、IndieWeb Living Standard 11 July 2024で定義されているJSONドキュメント形式に対応しました
diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts
index 10b1199bbb..3d4ecbf75b 100644
--- a/packages/frontend/src/boot/main-boot.ts
+++ b/packages/frontend/src/boot/main-boot.ts
@@ -29,6 +29,7 @@ import { prefer } from '@/preferences.js';
import { updateCurrentAccountPartial } from '@/accounts.js';
import { migrateOldSettings } from '@/pref-migrate.js';
import { unisonReload } from '@/utility/unison-reload.js';
+import { isBirthday } from '@/utility/is-birthday.js';
export async function mainBoot() {
const { isClientUpdated, lastVersion } = await common(async () => {
@@ -144,12 +145,8 @@ export async function mainBoot() {
const m = now.getMonth() + 1;
const d = now.getDate();
- if ($i.birthday) {
- const bm = parseInt($i.birthday.split('-')[1]);
- const bd = parseInt($i.birthday.split('-')[2]);
- if (m === bm && d === bd) {
- claimAchievement('loggedInOnBirthday');
- }
+ if (isBirthday($i, now)) {
+ claimAchievement('loggedInOnBirthday');
}
if (m === 1 && d === 1) {
diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue
index b61c84cbbc..ee04ca9e4a 100644
--- a/packages/frontend/src/pages/user/home.vue
+++ b/packages/frontend/src/pages/user/home.vue
@@ -186,6 +186,7 @@ import { getStaticImageUrl } from '@/utility/media-proxy.js';
import MkSparkle from '@/components/MkSparkle.vue';
import { prefer } from '@/preferences.js';
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
+import { isBirthday } from '@/utility/is-birthday.js';
function calcAge(birthdate: string): number {
const date = new Date(birthdate);
@@ -319,16 +320,10 @@ function disposeBannerParallaxResizeObserver() {
onMounted(() => {
narrow.value = rootEl.value!.clientWidth < 1000;
- if (props.user.birthday) {
- const m = new Date().getMonth() + 1;
- const d = new Date().getDate();
- const bm = parseInt(props.user.birthday.split('-')[1]);
- const bd = parseInt(props.user.birthday.split('-')[2]);
- if (m === bm && d === bd) {
- confetti({
- duration: 1000 * 4,
- });
- }
+ if (isBirthday(user.value)) {
+ confetti({
+ duration: 1000 * 4,
+ });
}
nextTick(() => {
diff --git a/packages/frontend/src/utility/is-birthday.ts b/packages/frontend/src/utility/is-birthday.ts
new file mode 100644
index 0000000000..ff875281a2
--- /dev/null
+++ b/packages/frontend/src/utility/is-birthday.ts
@@ -0,0 +1,28 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import * as Misskey from 'misskey-js';
+
+export function isBirthday(user: Misskey.entities.UserDetailed, now = new Date()): boolean {
+ if (user.birthday == null) return false;
+
+ const [_, bm, bd] = user.birthday.split('-').map((v) => parseInt(v, 10));
+ if (isNaN(bm) || isNaN(bd)) return false;
+
+ const y = now.getFullYear();
+ const m = now.getMonth() + 1;
+ const d = now.getDate();
+
+ // 閏日生まれで平年の場合は3月1日を誕生日として扱う
+ if (bm === 2 && bd === 29 && m === 3 && d === 1 && !isLeapYear(y)) {
+ return true;
+ }
+
+ return m === bm && d === bd;
+}
+
+function isLeapYear(year: number): boolean {
+ return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
+}
diff --git a/packages/frontend/test/is-birthday.test.ts b/packages/frontend/test/is-birthday.test.ts
new file mode 100644
index 0000000000..a072db4416
--- /dev/null
+++ b/packages/frontend/test/is-birthday.test.ts
@@ -0,0 +1,55 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import * as Misskey from 'misskey-js';
+import { describe, test, expect } from 'vitest';
+import { isBirthday } from '@/utility/is-birthday.js';
+
+describe('isBirthday', () => {
+ test('通常の誕生日', () => {
+ const currentDate = new Date('2024-05-15');
+ const result = isBirthday({
+ birthday: '2000-05-15',
+ } as Misskey.entities.UserDetailed, currentDate);
+
+ expect(result).toBe(true);
+ });
+
+ test('誕生日ではない場合', () => {
+ const currentDate = new Date('2024-05-15');
+ const result = isBirthday({
+ birthday: '2000-06-20',
+ } as Misskey.entities.UserDetailed, currentDate);
+
+ expect(result).toBe(false);
+ });
+
+ test('平年に閏日生まれを見た際に3月1日を誕生日とする', () => {
+ const currentDate = new Date('2023-03-01');
+ const result = isBirthday({
+ birthday: '2000-02-29',
+ } as Misskey.entities.UserDetailed, currentDate);
+
+ expect(result).toBe(true);
+ });
+
+ test('閏年に閏日生まれを見た際に2月29日を誕生日とする', () => {
+ const currentDate = new Date('2024-02-29');
+ const result = isBirthday({
+ birthday: '2000-02-29',
+ } as Misskey.entities.UserDetailed, currentDate);
+
+ expect(result).toBe(true);
+ });
+
+ test('閏年に閏日生まれを見た際に3月1日を誕生日としない', () => {
+ const currentDate = new Date('2024-03-01');
+ const result = isBirthday({
+ birthday: '2000-02-29',
+ } as Misskey.entities.UserDetailed, currentDate);
+
+ expect(result).toBe(false);
+ });
+});