mirror of
https://github.com/meineerde/redmine.git
synced 2025-12-19 15:01:14 +00:00
Replace Date.today with User.current.today (#22320).
Depending on the offset between a user's configured timezone and the server timezone, Date.today may be more or less often wrong from the user's perspective, leading to things like issues marked as overdue too early or too late, or yesterday / tomorrow being displayed / selected where 'today' is intended. A test case illustrating the problem with Issue#overdue? is included Patch by Jens Kraemer. git-svn-id: http://svn.redmine.org/redmine/trunk@15379 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
40c9c3e922
commit
ed50d42210
@ -27,7 +27,7 @@ class ActivitiesController < ApplicationController
|
||||
begin; @date_to = params[:from].to_date + 1; rescue; end
|
||||
end
|
||||
|
||||
@date_to ||= Date.today + 1
|
||||
@date_to ||= User.current.today + 1
|
||||
@date_from = @date_to - @days
|
||||
@with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
|
||||
if params[:user_id].present?
|
||||
|
||||
@ -35,8 +35,8 @@ class CalendarsController < ApplicationController
|
||||
@month = params[:month].to_i
|
||||
end
|
||||
end
|
||||
@year ||= Date.today.year
|
||||
@month ||= Date.today.month
|
||||
@year ||= User.current.today.year
|
||||
@month ||= User.current.today.month
|
||||
|
||||
@calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), current_language, :month)
|
||||
retrieve_query
|
||||
|
||||
@ -441,7 +441,7 @@ class IssuesController < ApplicationController
|
||||
@issue.project ||= @issue.allowed_target_projects.first
|
||||
end
|
||||
@issue.author ||= User.current
|
||||
@issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date?
|
||||
@issue.start_date ||= User.current.today if Setting.default_issue_start_date_to_creation_date?
|
||||
|
||||
attrs = (params[:issue] || {}).deep_dup
|
||||
if action_name == 'new' && params[:was_default_status] == attrs[:status_id]
|
||||
|
||||
@ -352,7 +352,7 @@ class RepositoriesController < ApplicationController
|
||||
end
|
||||
|
||||
def graph_commits_per_month(repository)
|
||||
@date_to = Date.today
|
||||
@date_to = User.current.today
|
||||
@date_from = @date_to << 11
|
||||
@date_from = Date.civil(@date_from.year, @date_from.month, 1)
|
||||
commits_by_day = Changeset.
|
||||
@ -371,7 +371,8 @@ class RepositoriesController < ApplicationController
|
||||
changes_by_day.each {|c| changes_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last }
|
||||
|
||||
fields = []
|
||||
12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)}
|
||||
today = User.current.today
|
||||
12.times {|m| fields << month_name(((today.month - 1 - m) % 12) + 1)}
|
||||
|
||||
graph = SVG::Graph::Bar.new(
|
||||
:height => 300,
|
||||
|
||||
@ -252,7 +252,7 @@ module ApplicationHelper
|
||||
|
||||
def due_date_distance_in_words(date)
|
||||
if date
|
||||
l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
|
||||
l((date < User.current.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(User.current.today, date))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@ module MyHelper
|
||||
|
||||
def timelog_items
|
||||
TimeEntry.
|
||||
where("#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", User.current.id, Date.today - 6, Date.today).
|
||||
where("#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", User.current.id, User.current.today - 6, User.current.today).
|
||||
joins(:activity, :project).
|
||||
references(:issue => [:tracker, :status]).
|
||||
includes(:issue => [:tracker, :status]).
|
||||
|
||||
@ -182,7 +182,7 @@ module SettingsHelper
|
||||
# Returns the options for the date_format setting
|
||||
def date_format_setting_options(locale)
|
||||
Setting::DATE_FORMATS.map do |f|
|
||||
today = ::I18n.l(Date.today, :locale => locale, :format => f)
|
||||
today = ::I18n.l(User.current.today, :locale => locale, :format => f)
|
||||
format = f.gsub('%', '').gsub(/[dmY]/) do
|
||||
{'d' => 'dd', 'm' => 'mm', 'Y' => 'yyyy'}[$&]
|
||||
end
|
||||
|
||||
@ -807,14 +807,14 @@ class Issue < ActiveRecord::Base
|
||||
|
||||
# Returns true if the issue is overdue
|
||||
def overdue?
|
||||
due_date.present? && (due_date < Date.today) && !closed?
|
||||
due_date.present? && (due_date < User.current.today) && !closed?
|
||||
end
|
||||
|
||||
# Is the amount of work done less than it should for the due date
|
||||
def behind_schedule?
|
||||
return false if start_date.nil? || due_date.nil?
|
||||
done_date = start_date + ((due_date - start_date + 1) * done_ratio / 100).floor
|
||||
return done_date <= Date.today
|
||||
return done_date <= User.current.today
|
||||
end
|
||||
|
||||
# Does this issue have children?
|
||||
|
||||
@ -206,7 +206,7 @@ class MailHandler < ActionMailer::Base
|
||||
issue.subject = '(no subject)'
|
||||
end
|
||||
issue.description = cleaned_up_text_body
|
||||
issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date?
|
||||
issue.start_date ||= User.current.today if Setting.default_issue_start_date_to_creation_date?
|
||||
issue.is_private = (handler_options[:issue][:is_private] == '1')
|
||||
|
||||
# add To and Cc as watchers before saving so the watchers can reply to Redmine
|
||||
|
||||
@ -594,7 +594,7 @@ class Project < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def overdue?
|
||||
active? && !due_date.nil? && (due_date < Date.today)
|
||||
active? && !due_date.nil? && (due_date < User.current.today)
|
||||
end
|
||||
|
||||
# Returns the percent completed for this project, based on the
|
||||
|
||||
@ -874,32 +874,32 @@ class Query < ActiveRecord::Base
|
||||
when "w"
|
||||
# = this week
|
||||
first_day_of_week = l(:general_first_day_of_week).to_i
|
||||
day_of_week = Date.today.cwday
|
||||
day_of_week = User.current.today.cwday
|
||||
days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week)
|
||||
sql = relative_date_clause(db_table, db_field, - days_ago, - days_ago + 6, is_custom_filter)
|
||||
when "lw"
|
||||
# = last week
|
||||
first_day_of_week = l(:general_first_day_of_week).to_i
|
||||
day_of_week = Date.today.cwday
|
||||
day_of_week = User.current.today.cwday
|
||||
days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week)
|
||||
sql = relative_date_clause(db_table, db_field, - days_ago - 7, - days_ago - 1, is_custom_filter)
|
||||
when "l2w"
|
||||
# = last 2 weeks
|
||||
first_day_of_week = l(:general_first_day_of_week).to_i
|
||||
day_of_week = Date.today.cwday
|
||||
day_of_week = User.current.today.cwday
|
||||
days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week)
|
||||
sql = relative_date_clause(db_table, db_field, - days_ago - 14, - days_ago - 1, is_custom_filter)
|
||||
when "m"
|
||||
# = this month
|
||||
date = Date.today
|
||||
date = User.current.today
|
||||
sql = date_clause(db_table, db_field, date.beginning_of_month, date.end_of_month, is_custom_filter)
|
||||
when "lm"
|
||||
# = last month
|
||||
date = Date.today.prev_month
|
||||
date = User.current.today.prev_month
|
||||
sql = date_clause(db_table, db_field, date.beginning_of_month, date.end_of_month, is_custom_filter)
|
||||
when "y"
|
||||
# = this year
|
||||
date = Date.today
|
||||
date = User.current.today
|
||||
sql = date_clause(db_table, db_field, date.beginning_of_year, date.end_of_year, is_custom_filter)
|
||||
when "~"
|
||||
sql = sql_contains("#{db_table}.#{db_field}", value.first)
|
||||
@ -999,7 +999,7 @@ class Query < ActiveRecord::Base
|
||||
|
||||
# Returns a SQL clause for a date or datetime field using relative dates.
|
||||
def relative_date_clause(table, field, days_from, days_to, is_custom_filter)
|
||||
date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil), is_custom_filter)
|
||||
date_clause(table, field, (days_from ? User.current.today + days_from : nil), (days_to ? User.current.today + days_to : nil), is_custom_filter)
|
||||
end
|
||||
|
||||
# Returns a Date or Time from the given filter value
|
||||
|
||||
@ -512,6 +512,7 @@ class User < Principal
|
||||
if time_zone.nil?
|
||||
Date.today
|
||||
else
|
||||
# TODO replace with time_zone.today
|
||||
Time.now.in_time_zone(time_zone).to_date
|
||||
end
|
||||
end
|
||||
|
||||
@ -104,7 +104,7 @@ class Version < ActiveRecord::Base
|
||||
|
||||
# Returns true if the version is completed: closed or due date reached and no open issues
|
||||
def completed?
|
||||
closed? || (effective_date && (effective_date < Date.today) && (open_issues_count == 0))
|
||||
closed? || (effective_date && (effective_date < User.current.today) && (open_issues_count == 0))
|
||||
end
|
||||
|
||||
def behind_schedule?
|
||||
@ -112,7 +112,7 @@ class Version < ActiveRecord::Base
|
||||
return false
|
||||
elsif due_date && start_date
|
||||
done_date = start_date + ((due_date - start_date+1)* completed_percent/100).floor
|
||||
return done_date <= Date.today
|
||||
return done_date <= User.current.today
|
||||
else
|
||||
false # No issues so it's not late
|
||||
end
|
||||
@ -141,7 +141,7 @@ class Version < ActiveRecord::Base
|
||||
|
||||
# Returns true if the version is overdue: due date reached and some open issues
|
||||
def overdue?
|
||||
effective_date && (effective_date < Date.today) && (open_issues_count > 0)
|
||||
effective_date && (effective_date < User.current.today) && (open_issues_count > 0)
|
||||
end
|
||||
|
||||
# Returns assigned issues count
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
<%= link_to_content_update(l(:label_next) + " \xc2\xbb",
|
||||
params.merge(:from => @date_to + @days - 1),
|
||||
:title => l(:label_date_from_to, :start => format_date(@date_to), :end => format_date(@date_to + @days - 1)),
|
||||
:accesskey => accesskey(:next)) unless @date_to >= Date.today %>
|
||||
:accesskey => accesskey(:next)) unless @date_to >= User.current.today %>
|
||||
</div>
|
||||
|
||||
<% other_formats_links do |f| %>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<% day = calendar.startdt
|
||||
while day <= calendar.enddt %>
|
||||
<%= ("<td class='week-number' title='#{ l(:label_week) }'>#{(day+(11-day.cwday)%7).cweek}</td>".html_safe) if day.cwday == calendar.first_wday %>
|
||||
<td class="<%= day.month==calendar.month ? 'even' : 'odd' %><%= ' today' if Date.today == day %>">
|
||||
<td class="<%= day.month==calendar.month ? 'even' : 'odd' %><%= ' today' if User.current.today == day %>">
|
||||
<p class="day-num"><%= day.day %></p>
|
||||
<% calendar.events_on(day).each do |i| %>
|
||||
<% if i.is_a? Issue %>
|
||||
|
||||
@ -302,9 +302,9 @@
|
||||
<%= @gantt.lines.html_safe %>
|
||||
|
||||
<% ###### Today red line (excluded from cache) ###### %>
|
||||
<% if Date.today >= @gantt.date_from and Date.today <= @gantt.date_to %>
|
||||
<% if User.current.today >= @gantt.date_from and User.current.today <= @gantt.date_to %>
|
||||
<%
|
||||
today_left = (((Date.today - @gantt.date_from + 1) * zoom).floor() - 1).to_i
|
||||
today_left = (((User.current.today - @gantt.date_from + 1) * zoom).floor() - 1).to_i
|
||||
style = ""
|
||||
style += "position: absolute;"
|
||||
style += "height: #{g_height}px;"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<h3><%= l(:label_calendar) %></h3>
|
||||
|
||||
<% calendar = Redmine::Helpers::Calendar.new(Date.today, current_language, :week)
|
||||
<% calendar = Redmine::Helpers::Calendar.new(User.current.today, current_language, :week)
|
||||
calendar.events = calendar_items(calendar.startdt, calendar.enddt) %>
|
||||
|
||||
<%= render :partial => 'common/calendar', :locals => {:calendar => calendar } %>
|
||||
|
||||
@ -29,7 +29,7 @@ entries_by_day = entries.group_by(&:spent_on)
|
||||
<tbody>
|
||||
<% entries_by_day.keys.sort.reverse.each do |day| %>
|
||||
<tr class="odd">
|
||||
<td><strong><%= day == Date.today ? l(:label_today).titleize : format_date(day) %></strong></td>
|
||||
<td><strong><%= day == User.current.today ? l(:label_today).titleize : format_date(day) %></strong></td>
|
||||
<td colspan="2"></td>
|
||||
<td class="hours"><em><%= html_hours("%.2f" % entries_by_day[day].sum(&:hours).to_f) %></em></td>
|
||||
<td></td>
|
||||
|
||||
@ -26,7 +26,7 @@ module Redmine
|
||||
pdf = ITCPDF.new(current_language)
|
||||
pdf.set_title("#{issue.project} - #{issue.tracker} ##{issue.id}")
|
||||
pdf.alias_nb_pages
|
||||
pdf.footer_date = format_date(Date.today)
|
||||
pdf.footer_date = format_date(User.current.today)
|
||||
pdf.add_page
|
||||
pdf.SetFontStyle('B',11)
|
||||
buf = "#{issue.project} - #{issue.tracker} ##{issue.id}"
|
||||
@ -246,7 +246,7 @@ module Redmine
|
||||
title = "#{project} - #{title}" if project
|
||||
pdf.set_title(title)
|
||||
pdf.alias_nb_pages
|
||||
pdf.footer_date = format_date(Date.today)
|
||||
pdf.footer_date = format_date(User.current.today)
|
||||
pdf.set_auto_page_break(false)
|
||||
pdf.add_page("L")
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ module Redmine
|
||||
pdf = Redmine::Export::PDF::ITCPDF.new(current_language)
|
||||
pdf.set_title(project.name)
|
||||
pdf.alias_nb_pages
|
||||
pdf.footer_date = format_date(Date.today)
|
||||
pdf.footer_date = format_date(User.current.today)
|
||||
pdf.add_page
|
||||
pdf.SetFontStyle('B',11)
|
||||
pdf.RDMMultiCell(190,5, project.name)
|
||||
@ -43,7 +43,7 @@ module Redmine
|
||||
pdf = ITCPDF.new(current_language)
|
||||
pdf.set_title("#{project} - #{page.title}")
|
||||
pdf.alias_nb_pages
|
||||
pdf.footer_date = format_date(Date.today)
|
||||
pdf.footer_date = format_date(User.current.today)
|
||||
pdf.add_page
|
||||
pdf.SetFontStyle('B',11)
|
||||
pdf.RDMMultiCell(190,5,
|
||||
|
||||
@ -59,8 +59,8 @@ module Redmine
|
||||
@month_from = 1
|
||||
end
|
||||
else
|
||||
@month_from ||= Date.today.month
|
||||
@year_from ||= Date.today.year
|
||||
@month_from ||= User.current.today.month
|
||||
@year_from ||= User.current.today.year
|
||||
end
|
||||
zoom = (options[:zoom] || User.current.pref[:gantt_zoom]).to_i
|
||||
@zoom = (zoom > 0 && zoom < 5) ? zoom : 2
|
||||
@ -428,9 +428,9 @@ module Redmine
|
||||
lines(:image => gc, :top => top, :zoom => zoom,
|
||||
:subject_width => subject_width, :format => :image)
|
||||
# today red line
|
||||
if Date.today >= @date_from and Date.today <= date_to
|
||||
if User.current.today >= @date_from and User.current.today <= date_to
|
||||
gc.stroke('red')
|
||||
x = (Date.today - @date_from + 1) * zoom + subject_width
|
||||
x = (User.current.today - @date_from + 1) * zoom + subject_width
|
||||
gc.line(x, headers_height, x, headers_height + g_height - 1)
|
||||
end
|
||||
gc.draw(imgl)
|
||||
@ -442,7 +442,7 @@ module Redmine
|
||||
pdf = ::Redmine::Export::PDF::ITCPDF.new(current_language)
|
||||
pdf.SetTitle("#{l(:label_gantt)} #{project}")
|
||||
pdf.alias_nb_pages
|
||||
pdf.footer_date = format_date(Date.today)
|
||||
pdf.footer_date = format_date(User.current.today)
|
||||
pdf.AddPage("L")
|
||||
pdf.SetFontStyle('B', 12)
|
||||
pdf.SetX(15)
|
||||
@ -592,8 +592,8 @@ module Redmine
|
||||
coords[:bar_progress_end] = self.date_to - self.date_from + 1
|
||||
end
|
||||
end
|
||||
if progress_date < Date.today
|
||||
late_date = [Date.today, end_date].min
|
||||
if progress_date < User.current.today
|
||||
late_date = [User.current.today, end_date].min
|
||||
if late_date > self.date_from && late_date > start_date
|
||||
if late_date < self.date_to
|
||||
coords[:bar_late_end] = late_date - self.date_from + 1
|
||||
|
||||
@ -70,10 +70,10 @@ module Redmine
|
||||
end
|
||||
|
||||
min = @hours.collect {|row| row['spent_on']}.min
|
||||
@from = min ? min.to_date : Date.today
|
||||
@from = min ? min.to_date : User.current.today
|
||||
|
||||
max = @hours.collect {|row| row['spent_on']}.max
|
||||
@to = max ? max.to_date : Date.today
|
||||
@to = max ? max.to_date : User.current.today
|
||||
|
||||
@total_hours = @hours.inject(0) {|s,k| s = s + k['hours'].to_f}
|
||||
|
||||
|
||||
@ -2756,4 +2756,30 @@ class IssueTest < ActiveSupport::TestCase
|
||||
issue.reload.assigned_to = nil
|
||||
assert_equal group, issue.assigned_to_was
|
||||
end
|
||||
|
||||
def test_issue_overdue_should_respect_user_timezone
|
||||
user_in_europe = users(:users_001)
|
||||
user_in_europe.pref.update_attribute :time_zone, 'UTC'
|
||||
|
||||
user_in_asia = users(:users_002)
|
||||
user_in_asia.pref.update_attribute :time_zone, 'Hongkong'
|
||||
|
||||
issue = Issue.generate! :due_date => Date.parse('2016-03-20')
|
||||
|
||||
# server time is UTC
|
||||
time = Time.parse '2016-03-20 20:00 UTC'
|
||||
Time.stubs(:now).returns(time)
|
||||
Date.stubs(:today).returns(time.to_date)
|
||||
|
||||
# for a user in the same time zone as the server the issue is not overdue
|
||||
# yet
|
||||
User.current = user_in_europe
|
||||
assert !issue.overdue?
|
||||
|
||||
# at the same time, a user in East Asia looks at the issue - it's already
|
||||
# March 21st and the issue should be marked overdue
|
||||
User.current = user_in_asia
|
||||
assert issue.overdue?
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user