5

私のJavaアプリケーションは、すべてのユーザーに1日1回メールを送信する必要があります。各ユーザーの現地時間に基づいて、午前2時頃に配信したいと思います。したがって、ニューヨークのユーザーは、午前2時のアメリカ/ニューヨークの時間にメッセージを受け取ります。ロサンゼルスのユーザーは、午前2時のアメリカ/Los_Angelesの時間にメッセージを受け取ります。私の郵送プロセスは、1日の1時間に1回実行されます。

HTML5ジオロケーション機能またはIPアドレスジオロケーションを使用して、サインアップ時に各ユーザーのタイムゾーンを自動的に決定する予定です。もちろん、これらの値が正しくない場合、ユーザーはタイムゾーンを手動で変更できます。選択したタイムゾーンを「America/New_York」などのタイムゾーンID文字列としてUserオブジェクトに保存するつもりです。これは文字列としてデータベースに保持されますが、必要に応じて変更できます。

考慮事項:

  • 夏時間を考慮する必要があるため、ユーザーは常に午前2時頃にメールを受信します。これは、GMT-8または同様のUTCオフセットをユーザーオブジェクトに保存することはできないことを意味します。ロサンゼルスはGMT-7であり、他の部分はGMT-8です。
  • 別のSOの質問には、オフセット情報を保存することを提案する回答がありますが、さまざまな場所の時間が1年を通して変化する可能性があるため、それがどのように機能するかわかりません。世界のどこかでタイムゾーン変更イベントが発生するたびに、すべてのユーザーオブジェクトのタイムゾーンを更新するつもりはありません。
  • 私は自分のアプリケーションでJodaTimeを使用しているので、それが役立つ場合はそれを利用できます。
  • 私はデータベースクエリにHibernateを使用しており、Javaで数十万のユーザーレコードを処理する必要なしに、Hibernateクエリで処理できるソリューションを見つけたいと考えています。

私はSpringSchedulingcron機能(Quartz経由)を使用して、1日の1時間ごとに1時間の2分後にメソッドを実行しています。現在、私のユーザーのほとんどはAmerica / Los_Angelesにいるので、すべてのメールを太平洋時間の午前2:02に手動で送信するように強制しています。次のメソッドは、毎時1時02分に実行されますが、手動で時刻をチェックし、ロサンゼルスの現在の時刻が2:00時間である場合にのみ続行します。これは、他の場所のユーザーが午前2時とは異なる時間にメールを受信することを意味します。

@Scheduled(cron="0 2 * * * *")
public void sendDailyReportEmail()  {
    DateTime now = new DateTime(DateTimeZone.forID("America/Los_Angeles"));
    if (now.getHourOfDay() != 2) {
        log.info("Not 2AM pacific, so skipping email reports");
        return;
    }
    // send email reports
}

したがって、必要なのは、Userオブジェクトのタイムゾーンに基づいて、午前2時の現地時間を持っているすべてのユーザーを取得するデータベースクエリを実行することです。これを達成する方法について何か考えはありますか?

4

1 に答える 1

3

私はこれをもっと考えて、可能な解決策を持っています。まだ実装していませんが、うまくいくと思います。基本的に、次のクエリを実行する必要があります (注: これは MySQL 固有のものです)。

select * from members where hour(convert_tz(now(),'UTC',timezone)) = 3;

このクエリは、次のようにして、現在の現地時間が午前 3 時から午前 3 時 59 分の間であるすべてのメンバーを選択します。

  1. を使用して現在のサーバー時刻を取得しますnow()。これは、データベース サーバーが UTC 時刻用に構成されているため、UTC の時刻です。
  2. 次に、メンバー テーブルの列でconvert_tz()指定されているように、関数を使用してその時間をメンバーのタイムゾーンに変換します。timezoneMember クラスには、「America/Los_Angeles」という形式のタイムゾーン フィールドが含まれていることに注意してください。
  3. 次に、午前 3 時hour()かどうかを関数で確認します3
  4. 次に、クエリは、これらの要件を満たすすべてのメンバーを返し、それぞれに電子メールを送信します。

システム内のすべてのメンバーに対して、このタイムゾーンの変換と計算を 1 時間ごとに行うことについて、少し心配しています。データベースにどのような負荷がかかるかをテストする必要がありますが、おそらく数百万人または数万人のユーザーで窒息するでしょう.

負荷を大幅に軽減する必要がありますが、それほど洗練されていない別の方法は、次のようにすることです (このコードはテストされていないことに注意してください!)。

@Scheduled(cron="0 2 * * * *")
public void sendDailyReportEmail()  {

    Query query = session.createQuery(
        "select distinct m.timezone from Member m");
    List<String> timezones = query.list();

    for (String timezone : timezones) {
        DateTime now = new DateTime(DateTimeZone.forID(timezone));
        if (now.getHourOfDay() == 3) {
            Query query2 = session.createQuery(
                "from Member where timezone = :zone");
            query2.setParameter("zone", timezone);
            List<Member> members = query2.list();
            // send email reports
        }
    }
}

このコードはこれを行います:

  1. 毎日、毎正時 2 分にメソッドを実行する
  2. members テーブル内のすべての一意のタイムゾーンのリストについて、データベースにクエリを実行します。
  3. 見つかったタイムゾーンごとに、現在午前 3 時かどうかを判断します。
  4. タイムゾーンが午前 3 時である場合は、そのタイムゾーンのすべてのメンバーを選択して、電子メールを送信します。

これにより、各時間の開始時にオーバーヘッドが少し追加されますが、ユーザーごとのタイムゾーン処理は必要ありません。システムが実際に使用する一意のタイム ゾーンは、数十しかない可能性があります。500 以上のタイムゾーンすべてにメンバーがいる可能性はほとんどありません。

最後に一つだけ。午前 2 時にメールを送信する代わりに、午前 3 時にメールを送信しました。これは、春にサマータイムが変わると、時刻が午前 2 時から午前 3 時に変わるためです。したがって、午前 2 時 2 分などというものはありません。つまり、その日にメールは送信されません。さらに、秋には、1 時間が繰り返されるため、システムはユーザーごとに 2 つの電子メールを送信できます。午前 3 時は別の場所で問題になる可能性があるため、米国以外のタイムゾーンが異なる時間に時刻を変更するかどうかを確認する必要があります。

于 2010-12-03T12:57:45.313 に答える