relative date formatting + refactoring

This commit is contained in:
Anton Makeev
2010-09-26 14:04:04 +04:00
parent 99a08c116c
commit 31a3d4fa30
23 changed files with 259 additions and 247 deletions
@@ -1,34 +0,0 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.history;
public class Clock {
private static long myTimestamp = -1;
public static long getCurrentTimestamp() {
if (myTimestamp != -1) return myTimestamp;
return System.currentTimeMillis();
}
public static void setCurrentTimestamp(long t) {
myTimestamp = t;
}
public static void useRealClock() {
myTimestamp = -1;
}
}
@@ -16,12 +16,12 @@
package com.intellij.history.core;
import com.intellij.history.Clock;
import com.intellij.history.core.changes.Change;
import com.intellij.history.core.changes.ChangeSet;
import com.intellij.history.core.changes.ChangeVisitor;
import com.intellij.history.utils.LocalHistoryLog;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Clock;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.TestOnly;
@@ -70,7 +70,7 @@ public class ChangeList {
}
private void doBeginChangeSet() {
myCurrentChangeSet = new ChangeSet(myStorage.nextId(), Clock.getCurrentTimestamp());
myCurrentChangeSet = new ChangeSet(myStorage.nextId(), Clock.getTime());
}
public synchronized boolean forceBeginChangeSet() {
@@ -15,7 +15,7 @@
*/
package com.intellij.history.core;
import com.intellij.history.Clock;
import com.intellij.openapi.util.Clock;
import com.intellij.util.io.PagePool;
import com.intellij.util.io.storage.AbstractRecordsTable;
import com.intellij.util.io.storage.AbstractStorage;
@@ -100,7 +100,7 @@ public class LocalHistoryStorage extends AbstractStorage {
}
table.setLastRecord(id);
table.setTimestamp(id, Clock.getCurrentTimestamp());
table.setTimestamp(id, Clock.getTime());
return id;
}
@@ -16,7 +16,6 @@
package com.intellij.history.integration;
import com.intellij.history.Clock;
import com.intellij.history.core.Content;
import com.intellij.history.core.LocalHistoryFacade;
import com.intellij.history.core.Paths;
@@ -33,6 +32,7 @@ import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Clock;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.CharsetToolkit;
@@ -218,7 +218,7 @@ public class IdeaGateway {
private void registerDocumentContents(LocalHistoryFacade vcs, VirtualFile f, Document d) {
Content content = acquireAndUpdateActualContent(f, d);
if (content != null) {
vcs.contentChanged(f.getPath(), content, Clock.getCurrentTimestamp());
vcs.contentChanged(f.getPath(), content, Clock.getTime());
}
}
@@ -25,8 +25,8 @@ import com.intellij.history.integration.LocalHistoryBundle;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.text.DateFormatUtil;
import java.io.IOException;
import java.util.*;
@@ -97,7 +97,7 @@ public abstract class Reverter {
public String getCommandName() {
Revision to = getTargetRevision();
String name = to.getChangeSetName();
String date = StringUtil.formatDateTime(to.getTimestamp());
String date = DateFormatUtil.formatExactDateTime(to.getTimestamp());
if (name != null) {
return LocalHistoryBundle.message("system.label.revert.to.change.date", name, date);
}
@@ -24,7 +24,7 @@ import com.intellij.openapi.diff.SimpleContent;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.text.DateFormatUtil;
public abstract class FileDifferenceModel {
protected final Project myProject;
@@ -58,7 +58,7 @@ public abstract class FileDifferenceModel {
}
private String formatTitle(Entry e, boolean isAvailable) {
String result = StringUtil.formatRelativeDateTime(e.getTimestamp()) + " - " + e.getName();
String result = DateFormatUtil.formatDateTime(e.getTimestamp()) + " - " + e.getName();
if (!isAvailable) {
result += " - " + LocalHistoryBundle.message("content.not.available");
}
@@ -23,8 +23,8 @@ import com.intellij.history.integration.LocalHistoryBundle;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.components.JBList;
import com.intellij.util.text.DateFormatUtil;
import com.intellij.util.ui.UIUtil;
import javax.swing.*;
@@ -107,7 +107,7 @@ public class RecentChangesPopup {
public Component getListCellRendererComponent(JList l, Object val, int i, boolean isSelected, boolean cellHasFocus) {
RecentChange c = (RecentChange)val;
myActionLabel.setText(c.getChangeName());
myDateLabel.setText(StringUtil.formatRelativeDateTime(c.getTimestamp()));
myDateLabel.setText(DateFormatUtil.formatDateTime(c.getTimestamp()));
updateColors(isSelected);
return myPanel;
@@ -27,6 +27,7 @@ import com.intellij.ui.ExpandableItemsHandler;
import com.intellij.ui.SeparatorWithText;
import com.intellij.ui.TableCell;
import com.intellij.ui.table.JBTable;
import com.intellij.util.text.DateFormatUtil;
import com.intellij.util.ui.AbstractLayoutManager;
import com.intellij.util.ui.UIUtil;
import gnu.trove.THashMap;
@@ -303,7 +304,7 @@ public class RevisionsList {
myBorder.set(row == table.getModel().getRowCount() - 1);
myDateLabel.setText(ensureString(StringUtil.formatRelativeDateTime(r.revision.getTimestamp())));
myDateLabel.setText(ensureString(DateFormatUtil.formatDateTime(r.revision.getTimestamp())));
myFilesCountLabel.setText(ensureString(labelsAndColor.filesCount));
myTitleLabel.setFont(myTitleLabel.getFont().deriveFont(labelsAndColor.isNamed ? Font.BOLD : Font.PLAIN));
@@ -16,7 +16,6 @@
package com.intellij.history.core;
import com.intellij.history.Clock;
import com.intellij.history.core.changes.*;
import com.intellij.history.core.revisions.Revision;
import com.intellij.history.core.storage.TestContent;
@@ -24,6 +23,7 @@ import com.intellij.history.core.tree.Entry;
import com.intellij.history.core.tree.FileEntry;
import com.intellij.history.core.tree.RootEntry;
import com.intellij.history.integration.TestVirtualFile;
import com.intellij.openapi.util.Clock;
import org.jetbrains.annotations.Nullable;
import org.junit.Assert;
@@ -164,7 +164,7 @@ public abstract class LocalHistoryTestCase extends Assert {
}
protected static void setCurrentTimestamp(long t) {
Clock.setCurrentTimestamp(t);
Clock.setTime(t);
}
protected static void assertContent(String expected, Entry e) {
@@ -17,9 +17,9 @@
package com.intellij.history.integration;
import com.intellij.history.Clock;
import com.intellij.history.FileRevisionTimestampComparator;
import com.intellij.history.LocalHistory;
import com.intellij.openapi.util.Clock;
import com.intellij.openapi.vfs.VirtualFile;
public class GettingContentAtDateTest extends IntegrationTestCase {
@@ -49,11 +49,11 @@ public class GettingContentAtDateTest extends IntegrationTestCase {
}
public void testGettingFirstAvailableContentAfterPurge() throws Exception {
Clock.setCurrentTimestamp(1);
Clock.setTime(1);
setContent(f, "1", TIMESTAMP_INCREMENT);
Clock.setCurrentTimestamp(2);
Clock.setTime(2);
setContent(f, "2", TIMESTAMP_INCREMENT * 2);
Clock.setCurrentTimestamp(3);
Clock.setTime(3);
setContent(f, "3", TIMESTAMP_INCREMENT * 3);
getVcs().getChangeListInTests().purgeObsolete(2);
@@ -16,7 +16,6 @@
package com.intellij.history.integration;
import com.intellij.history.Clock;
import com.intellij.history.core.LocalHistoryFacade;
import com.intellij.history.core.LocalHistoryTestCase;
import com.intellij.history.core.Paths;
@@ -30,6 +29,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.Clock;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.testFramework.PlatformTestCase;
@@ -55,7 +55,7 @@ public abstract class IntegrationTestCase extends PlatformTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
Clock.useRealClock();
Clock.reset();
Paths.useSystemCaseSensitivity();
myGateway = new IdeaGateway();
@@ -79,7 +79,7 @@ public abstract class IntegrationTestCase extends PlatformTestCase {
@Override
protected void tearDown() throws Exception {
Clock.useRealClock();
Clock.reset();
Paths.useSystemCaseSensitivity();
super.tearDown();
}
@@ -15,11 +15,11 @@
*/
package com.intellij.history.integration;
import com.intellij.history.Clock;
import com.intellij.history.LocalHistory;
import com.intellij.history.core.LocalHistoryTestCase;
import com.intellij.history.core.changes.ChangeSet;
import com.intellij.history.core.revisions.Revision;
import com.intellij.openapi.util.Clock;
import com.intellij.openapi.vfs.VirtualFile;
import org.junit.Test;
@@ -98,11 +98,11 @@ public class PurgingTest extends IntegrationTestCase {
@Test
public void testChangesAfterPurge() throws IOException {
Clock.setCurrentTimestamp(1);
Clock.setTime(1);
VirtualFile f = createFile("file.txt");
Clock.setCurrentTimestamp(2);
Clock.setTime(2);
setContent(f, "1");
Clock.setCurrentTimestamp(3);
Clock.setTime(3);
setContent(f, "2");
assertEquals(3, LocalHistoryTestCase.collectChanges(getVcs(), f.getPath(), myProject.getLocationHash(), null).size());
@@ -114,10 +114,10 @@ public class PurgingTest extends IntegrationTestCase {
@Test
public void testLabelsAfterPurge() throws IOException {
Clock.setCurrentTimestamp(1);
Clock.setTime(1);
VirtualFile file = createFile("file");
Clock.setCurrentTimestamp(2);
Clock.setTime(2);
LocalHistory.getInstance().putUserLabel(myProject, "1");
getVcs().getChangeListInTests().purgeObsolete(1);
@@ -129,7 +129,7 @@ public class PurgingTest extends IntegrationTestCase {
private void createChangesWithTimestamps(long... tt) {
for (long t : tt) {
Clock.setCurrentTimestamp(t);
Clock.setTime(t);
getVcs().beginChangeSet();
getVcs().putUserLabel("foo", "project");
getVcs().endChangeSet(null);
@@ -17,11 +17,11 @@
package com.intellij.history.integration;
import com.intellij.history.Clock;
import com.intellij.history.LocalHistory;
import com.intellij.history.core.revisions.Difference;
import com.intellij.history.core.revisions.Revision;
import com.intellij.history.core.tree.Entry;
import com.intellij.openapi.util.Clock;
import com.intellij.openapi.vfs.VirtualFile;
import java.io.IOException;
@@ -53,7 +53,7 @@ public class RevisionsAndDiffsTest extends IntegrationTestCase {
}
public void testIncludingCurrentVersionIntoRevisionsAfterPurge() throws Exception {
Clock.setCurrentTimestamp(10);
Clock.setTime(10);
VirtualFile f = createFile("file.txt", "content");
getVcs().getChangeListInTests().purgeObsolete(0);
@@ -71,7 +71,7 @@ public class RevisionsAndDiffsTest extends IntegrationTestCase {
}
public void testCurrentRevisionForDirectoryAfterPurge() throws Exception {
Clock.setCurrentTimestamp(10);
Clock.setTime(10);
VirtualFile f = createDirectory("dir");
getVcs().getChangeListInTests().purgeObsolete(0);
@@ -88,9 +88,9 @@ public class RevisionsAndDiffsTest extends IntegrationTestCase {
}
public void testIncludingVersionBeforeFirstChangeAfterPurge() throws IOException {
Clock.setCurrentTimestamp(10);
Clock.setTime(10);
VirtualFile f = createFile("file.txt", "one");
Clock.setCurrentTimestamp(20);
Clock.setTime(20);
setContent(f, "two");
getVcs().getChangeListInTests().purgeObsolete(5);
@@ -117,13 +117,13 @@ public class RevisionsAndDiffsTest extends IntegrationTestCase {
}
public void testRevisionsTimestamp() throws IOException {
Clock.setCurrentTimestamp(10);
Clock.setTime(10);
VirtualFile f = createFile("file1.txt");
Clock.setCurrentTimestamp(20);
Clock.setTime(20);
setContent(f, "a");
Clock.setCurrentTimestamp(30);
Clock.setTime(30);
setContent(f, "b");
List<Revision> rr = getRevisionsFor(f);
@@ -140,13 +140,13 @@ public class RevisionsAndDiffsTest extends IntegrationTestCase {
}
public void testTimestampForLastRevisionAfterPurge() throws IOException {
Clock.setCurrentTimestamp(10);
Clock.setTime(10);
VirtualFile f = createFile("file1.txt");
Clock.setCurrentTimestamp(20);
Clock.setTime(20);
setContent(f, "a");
Clock.setCurrentTimestamp(30);
Clock.setTime(30);
setContent(f, "b");
getVcs().getChangeListInTests().purgeObsolete(15);
@@ -15,11 +15,11 @@
*/
package com.intellij.history.integration;
import com.intellij.history.Clock;
import com.intellij.history.core.changes.ChangeSet;
import com.intellij.history.core.changes.ChangeVisitor;
import com.intellij.history.core.changes.CreateEntryChange;
import com.intellij.history.core.changes.RenameChange;
import com.intellij.openapi.util.Clock;
import com.intellij.openapi.vfs.VirtualFile;
import org.junit.Test;
@@ -111,12 +111,12 @@ public class VisitingTest extends IntegrationTestCase {
@Test
public void testPurgingDuringVisit() throws Exception {
Clock.setCurrentTimestamp(10);
Clock.setTime(10);
getVcs().beginChangeSet();
createFile("f.txt");
getVcs().endChangeSet(null);
Clock.setCurrentTimestamp(20);
Clock.setTime(20);
getVcs().beginChangeSet();
createFile("dir");
getVcs().endChangeSet(null);
@@ -16,15 +16,15 @@
package com.intellij.history.integration.revertion;
import com.intellij.history.Clock;
import com.intellij.history.core.revisions.Revision;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.integration.IdeaGateway;
import com.intellij.history.integration.IntegrationTestCase;
import com.intellij.history.integration.ui.models.SelectionCalculator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.Clock;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.text.DateFormatUtil;
import java.io.IOException;
import java.util.ArrayList;
@@ -69,7 +69,7 @@ public class SelectionReverterTest extends IntegrationTestCase {
public void testChangeSetName() throws IOException {
long time = new Date(2001, 1, 11, 12, 30).getTime();
Clock.setCurrentTimestamp(time);
Clock.setTime(time);
f.setBinaryContent("one".getBytes());
f.setBinaryContent("two".getBytes());
@@ -78,7 +78,7 @@ public class SelectionReverterTest extends IntegrationTestCase {
List<Revision> rr = getRevisionsFor(f);
assertEquals(5, rr.size());
assertEquals("Reverted to " + StringUtil.formatDateTime(time), rr.get(1).getChangeSetName());
assertEquals("Reverted to " + DateFormatUtil.formatExactDateTime(time), rr.get(1).getChangeSetName());
}
public void testAskingForReadOnlyStatusClearingOnlyForTheSpecifiedFile() throws Exception {
@@ -25,8 +25,8 @@ import com.intellij.openapi.diff.DiffContent;
import com.intellij.openapi.diff.DocumentContent;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.text.DateFormatUtil;
import java.io.IOException;
import java.util.Date;
@@ -54,9 +54,9 @@ public class FileHistoryDialogTest extends LocalHistoryUITestCase {
FileHistoryDialogModel m = createFileModelAndSelectRevisions(f, 0, 2);
assertEquals(FileUtil.toSystemDependentName(f.getPath()), m.getDifferenceModel().getTitle());
assertEquals(StringUtil.formatRelativeDateTime(leftTime) + " - old.txt",
assertEquals(DateFormatUtil.formatDateTime(leftTime) + " - old.txt",
m.getDifferenceModel().getLeftTitle(new NullRevisionsProgress()));
assertEquals(StringUtil.formatRelativeDateTime(rightTime) + " - new.txt",
assertEquals(DateFormatUtil.formatDateTime(rightTime) + " - new.txt",
m.getDifferenceModel().getRightTitle(new NullRevisionsProgress()));
}
@@ -181,7 +181,7 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
if (message != null) {
StringBuffer txt = new StringBuffer();
txt.append(DiagnosticBundle.message("error.list.message.info",
DateFormatUtil.formatDate(new Date(), message.getDate()), myModel.get(myIndex).size()));
DateFormatUtil.formatDateTime(message.getDate()), myModel.get(myIndex).size()));
if (message.isSubmitted()) {
final SubmittedReportInfo info = message.getSubmissionInfo();
@@ -42,13 +42,13 @@ button.edit=Edit
button.remove=Remove
button.remove.r=&Remove
#Ddate format
#date format
date.format.less.than.a.minute=less than a minute
date.format.right.now=right now
date.format.yesterday=Yesterday
date.format.minutes.ago={0,choice, 0#Moments|1#A minute|2#{0,number} minutes|60#1 hour} ago
date.format.today=Today
date.format.yesterday=Yesterday
date.format.a.few.moments.ago=a few moments ago
date.format.in.a.few.moments=in a few moments
@@ -111,12 +111,6 @@ format.file.size.bytes={0}b
format.file.size.kbytes={0}Kb
format.file.size.mbytes={0}Mb
format.date.momentsAgo=Moments ago
format.date.fewMinutesAgo=Few minutes ago
format.date.last30Minutes=Last 30 minutes
format.date.lastHour=Last hour
format.date.hoursAgo={0} hours ago
profiling.captured.cpu.snapshot.message.text=Captured CPU snapshot:{0}.zip is placed in user home directory
profiling.captured.allocations.snapshot.message.text=Captured allocations snapshot:{0}.zip is placed in user home directory
information.dialog.title=Information
@@ -0,0 +1,56 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.util;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import java.util.Date;
public class Clock {
private static long ourTime = -1;
public static long getTime() {
if (ourTime != -1) return ourTime;
return System.currentTimeMillis();
}
@TestOnly
public static void setTime(long time) {
ourTime = time;
}
@TestOnly
public static void setTime(@NotNull Date date) {
setTime(date.getTime());
}
@TestOnly
public static void setTime(int year, int month, int day) {
setTime(year, month, day, 0, 0);
}
@TestOnly
public static void setTime(int year, int month, int day, int hours, int minutes) {
setTime(new Date(year - 1900, month, day, hours, minutes));
}
@TestOnly
public static void reset() {
ourTime = -1;
}
}
@@ -30,7 +30,6 @@ import org.jetbrains.annotations.Nullable;
import java.beans.Introspector;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -1122,61 +1121,6 @@ public class StringUtil {
return CommonBundle.message("format.file.size.mbytes", size);
}
// do not expose this constants - they are very likely to be changed in future
private static final DateFormat DATE_FORMAT_GENERAL = DateFormat.getDateInstance(DateFormat.SHORT);
private static final DateFormat TIME_FORMAT_GENERAL = DateFormat.getTimeInstance(DateFormat.SHORT);
private static final DateFormat DATE_TIME_FORMAT_GENERAL = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
@NotNull
public static DateFormat getDateFormat() {
return DATE_FORMAT_GENERAL;
}
@NotNull
public static DateFormat getTimeFormat() {
return TIME_FORMAT_GENERAL;
}
@NotNull
public static DateFormat getDateTimeFormat() {
return DATE_TIME_FORMAT_GENERAL;
}
@NotNull
public static String formatDateTime(long timestamp) {
return getDateTimeFormat().format(new Date(timestamp));
}
@NotNull
public static String formatRelativeDateTime(long timestamp) {
return formatRelative(timestamp, getDateTimeFormat());
}
@NotNull
public static String formatRelative(long timestamp, @NotNull DateFormat format) {
long minDelta = (new Date().getTime() - timestamp) / (1000 * 60);
if (minDelta < 2) {
return CommonBundle.message("format.date.momentsAgo");
}
if (minDelta < 10) {
return CommonBundle.message("format.date.fewMinutesAgo");
}
if (minDelta <= 30) {
return CommonBundle.message("format.date.last30Minutes");
}
int hoursDelta = Math.round(minDelta / 60f);
if (hoursDelta <= 1) {
return CommonBundle.message("format.date.lastHour");
}
if (hoursDelta < 5) {
return CommonBundle.message("format.date.hoursAgo", hoursDelta);
}
return format.format(timestamp);
}
@NotNull
private static String formatMinor(long number) {
if (number > 0L && number <= 9L) {
@@ -16,14 +16,19 @@
package com.intellij.util.text;
import com.intellij.CommonBundle;
import com.intellij.openapi.util.Clock;
import org.jetbrains.annotations.NotNull;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class DateFormatUtil {
// do not expose this constants - they are very likely to be changed in future
private static final DateFormat DATE_FORMAT = DateFormat.getDateInstance(DateFormat.SHORT);
private static final DateFormat TIME_FORMAT = DateFormat.getTimeInstance(DateFormat.SHORT);
private static final DateFormat DATE_TIME_FORMAT = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
public static final long SECOND = 1000;
public static final long MINUTE = SECOND * 60;
public static final long HOUR = MINUTE * 60;
@@ -31,18 +36,93 @@ public class DateFormatUtil {
public static final long WEEK = DAY * 7;
public static final long MONTH = DAY * 30;
public static final long YEAR = DAY * 365;
private static final long[] DELIMS = new long[]{YEAR, MONTH, WEEK, DAY, HOUR, MINUTE};
public static final long[] DELIMS = new long[] {YEAR, MONTH, WEEK, DAY, HOUR, MINUTE};
private enum Period {
YEAR, MONTH, WEEK, DAY, HOUR, MINUTE
}
private static final Period[] PERIOD = new Period[]{Period.YEAR, Period.MONTH, Period.WEEK, Period.DAY, Period.HOUR, Period.MINUTE};
private DateFormatUtil() {
}
enum Period {
YEAR, MONTH, WEEK, DAY, HOUR, MINUTE
@NotNull
public static DateFormat getDateFormat() {
return DATE_FORMAT;
}
private static final Period[] PERIOD = new Period[] {Period.YEAR, Period.MONTH, Period.WEEK, Period.DAY, Period.HOUR, Period.MINUTE};
@NotNull
public static DateFormat getTimeFormat() {
return TIME_FORMAT;
}
@NotNull
public static DateFormat getDateTimeFormat() {
return DATE_TIME_FORMAT;
}
@NotNull
public static String formatTime(long time) {
return getTimeFormat().format(time);
}
@NotNull
public static String formatDate(long time) {
return getDateFormat().format(time);
}
@NotNull
public static String formatExactDateTime(long time) {
return getDateTimeFormat().format(time);
}
@NotNull
public static String formatDateTime(Date time) {
return formatDateTime(time.getTime());
}
@NotNull
public static String formatDateTime(long time) {
return formatDateTime(time, DATE_TIME_FORMAT, TIME_FORMAT);
}
@NotNull
public static String formatDateTime(long time, @NotNull DateFormat dateTimeFormat, @NotNull DateFormat timeFormat) {
long currentTime = Clock.getTime();
Calendar c = Calendar.getInstance();
c.setTimeInMillis(currentTime);
int currentYear = c.get(Calendar.YEAR);
int currentDayOfYear = c.get(Calendar.DAY_OF_YEAR);
c.setTimeInMillis(time);
int year = c.get(Calendar.YEAR);
int dayOfYear = c.get(Calendar.DAY_OF_YEAR);
long delta = currentTime - time;
if (delta <= HOUR) {
return CommonBundle.message("date.format.minutes.ago", (int)Math.rint(delta / (double)MINUTE));
}
if (currentDayOfYear == dayOfYear) {
return CommonBundle.message("date.format.today") + " " + timeFormat.format(time);
}
boolean isYesterdayOnPreviousYear =
(currentYear == year + 1) && currentDayOfYear == 1 && dayOfYear == c.getActualMaximum(Calendar.DAY_OF_YEAR);
boolean isYesterday = isYesterdayOnPreviousYear || (currentYear == year && currentDayOfYear == dayOfYear + 1);
if (isYesterday) {
return CommonBundle.message("date.format.yesterday") + " " + timeFormat.format(time);
}
return dateTimeFormat.format(time);
}
@NotNull
public static String formatDuration(long delta) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < DELIMS.length; i++) {
@@ -60,16 +140,28 @@ public class DateFormatUtil {
}
private static String composeDurationMessage(final Period period, final int n) {
switch(period) {
case DAY: return CommonBundle.message("date.format.n.days", n);
case MINUTE:return CommonBundle.message("date.format.n.minutes", n);
case HOUR:return CommonBundle.message("date.format.n.hours", n);
case MONTH:return CommonBundle.message("date.format.n.months", n);
case WEEK:return CommonBundle.message("date.format.n.weeks", n);
default:return CommonBundle.message("date.format.n.years", n);
switch (period) {
case DAY:
return CommonBundle.message("date.format.n.days", n);
case MINUTE:
return CommonBundle.message("date.format.n.minutes", n);
case HOUR:
return CommonBundle.message("date.format.n.hours", n);
case MONTH:
return CommonBundle.message("date.format.n.months", n);
case WEEK:
return CommonBundle.message("date.format.n.weeks", n);
default:
return CommonBundle.message("date.format.n.years", n);
}
}
@NotNull
public static String formatFrequency(long time) {
return CommonBundle.message("date.frequency", formatBetweenDates(time, 0));
}
@NotNull
public static String formatBetweenDates(long d1, long d2) {
long delta = Math.abs(d1 - d2);
if (delta == 0) return CommonBundle.message("date.format.right.now");
@@ -87,83 +179,54 @@ public class DateFormatUtil {
if (d2 > d1) {
if (n <= 0) {
return CommonBundle.message("date.format.a.few.moments.ago");
} else {
}
else {
return someTimeAgoMessage(PERIOD[i], n);
}
}
else if (d2 < d1) {
if (n <= 0) {
return CommonBundle.message("date.format.in.a.few.moments");
} else {
}
else {
return composeInSomeTimeMessage(PERIOD[i], n);
}
}
return "";
}
private static String composeInSomeTimeMessage(final Period period, final int n) {
switch(period) {
case DAY: return CommonBundle.message("date.format.in.n.days", n);
case MINUTE:return CommonBundle.message("date.format.in.n.minutes", n);
case HOUR:return CommonBundle.message("date.format.in.n.hours", n);
case MONTH:return CommonBundle.message("date.format.in.n.months", n);
case WEEK:return CommonBundle.message("date.format.in.n.weeks", n);
default:return CommonBundle.message("date.format.in.n.years", n);
}
}
private static String someTimeAgoMessage(final Period period, final int n) {
switch(period) {
case DAY: return CommonBundle.message("date.format.n.days.ago", n);
case MINUTE:return CommonBundle.message("date.format.n.minutes.ago", n);
case HOUR:return CommonBundle.message("date.format.n.hours.ago", n);
case MONTH:return CommonBundle.message("date.format.n.months.ago", n);
case WEEK:return CommonBundle.message("date.format.n.weeks.ago", n);
default:return CommonBundle.message("date.format.n.years.ago", n);
}
}
public static String formatDate(Date today, Date date, Locale locale) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
int todayYear = calendar.get(Calendar.YEAR);
int todayDayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
DateFormat defaultDateFormat = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.SHORT,
SimpleDateFormat.SHORT,
locale);
DateFormat timeDefaultFormat = DateFormat.getTimeInstance(SimpleDateFormat.SHORT, locale);
boolean isYesterdayOnPreviousYear = (todayYear == year + 1) && todayDayOfYear == 1 && dayOfYear == calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
boolean isYesterday = isYesterdayOnPreviousYear || (todayYear == year && todayDayOfYear == dayOfYear + 1);
if (isYesterday) {
return CommonBundle.message("date.format.yesterday") + " " + timeDefaultFormat.format(date);
} else if (year != todayYear) {
return defaultDateFormat.format(date);
} else if (todayDayOfYear == dayOfYear) {
return CommonBundle.message("date.format.today") + " " + timeDefaultFormat.format(date);
} else {
return defaultDateFormat.format(date);
switch (period) {
case DAY:
return CommonBundle.message("date.format.n.days.ago", n);
case MINUTE:
return CommonBundle.message("date.format.n.minutes.ago", n);
case HOUR:
return CommonBundle.message("date.format.n.hours.ago", n);
case MONTH:
return CommonBundle.message("date.format.n.months.ago", n);
case WEEK:
return CommonBundle.message("date.format.n.weeks.ago", n);
default:
return CommonBundle.message("date.format.n.years.ago", n);
}
}
public static String formatDate(Date current_date, Date date) {
return formatDate(current_date, date, Locale.getDefault());
}
public static String formatFrequency(final long tm) {
return CommonBundle.message("date.frequency", formatBetweenDates(tm, 0));
private static String composeInSomeTimeMessage(final Period period, final int n) {
switch (period) {
case DAY:
return CommonBundle.message("date.format.in.n.days", n);
case MINUTE:
return CommonBundle.message("date.format.in.n.minutes", n);
case HOUR:
return CommonBundle.message("date.format.in.n.hours", n);
case MONTH:
return CommonBundle.message("date.format.in.n.months", n);
case WEEK:
return CommonBundle.message("date.format.in.n.weeks", n);
default:
return CommonBundle.message("date.format.in.n.years", n);
}
}
}
@@ -15,37 +15,38 @@
*/
package com.intellij.util;
import com.intellij.openapi.util.Clock;
import com.intellij.util.text.DateFormatUtil;
import junit.framework.TestCase;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class DateFormatUtilTest extends TestCase{
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy hh.mm.ss");
private Date myCurrentDate;
protected void setUp() throws Exception {
super.setUp();
}
public void test() throws ParseException {
myCurrentDate = DATE_FORMAT.parse("10.12.2004 15.53.27");
Clock.setTime(2004, 11, 10, 17, 0);
doTest("Today 3:00 PM", "10.12.2004 15.00.00");
doTest("Moments ago", "10.12.2004 16.59.31");
doTest("A minute ago", "10.12.2004 16.59.29");
doTest("5 minutes ago", "10.12.2004 16.55.00");
doTest("1 hour ago", "10.12.2004 16.00.00");
doTest("Today 3:55 PM", "10.12.2004 15.55.00");
doTest("Yesterday 3:00 PM", "09.12.2004 15.00.00");
doTest("12/8/04 3:00 PM", "08.12.2004 15.00.00");
doTest("12/7/04 3:00 PM", "07.12.2004 15.00.00");
myCurrentDate = DATE_FORMAT.parse("01.01.2004 15.53.27");
Clock.setTime(2004, 0, 1, 15, 53);
doTest("Yesterday 3:00 PM", "31.12.2003 15.00.00");
}
private void doTest(String expected, String date) throws ParseException {
assertEquals(expected, DateFormatUtil.formatDate(myCurrentDate, DATE_FORMAT.parse(date), Locale.US));
assertEquals(expected, DateFormatUtil.formatDateTime(DATE_FORMAT.parse(date)));
}
}
@@ -18,8 +18,6 @@ package com.intellij.util.text;
import com.intellij.openapi.util.text.StringUtil;
import junit.framework.TestCase;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
@@ -34,10 +32,10 @@ public class StringUtilTest extends TestCase {
assertEquals('A', StringUtil.toUpperCase('A'));
assertEquals('K', StringUtil.toUpperCase('k'));
assertEquals('K', StringUtil.toUpperCase('K'));
assertEquals('\u2567', StringUtil.toUpperCase(Character.toLowerCase('\u2567')));
}
public void testToLowerCase() {
assertEquals('/', StringUtil.toLowerCase('/'));
assertEquals(':', StringUtil.toLowerCase(':'));
@@ -72,15 +70,4 @@ public class StringUtilTest extends TestCase {
assertFalse(StringUtil.startsWithConcatenationOf("something", "something", "."));
assertFalse(StringUtil.startsWithConcatenationOf("some", "something", ""));
}
public void testFormattingDate() throws Exception {
assertEquals("Moments ago", StringUtil.formatRelative(new Date().getTime(), SimpleDateFormat.getDateTimeInstance()));
assertEquals("Few minutes ago", StringUtil.formatRelative(new Date().getTime() - (60 * 1000 * 2), SimpleDateFormat.getDateTimeInstance()));
assertEquals("Last 30 minutes", StringUtil.formatRelative(new Date().getTime() - (60 * 1000 * 30), SimpleDateFormat.getDateTimeInstance()));
assertEquals("Last hour", StringUtil.formatRelative(new Date().getTime() - (60 * 1000 * 80), SimpleDateFormat.getDateTimeInstance()));
assertEquals("2 hours ago", StringUtil.formatRelative(new Date().getTime() - (60 * 1000 * 100), SimpleDateFormat.getDateTimeInstance()));
assertEquals("3 hours ago", StringUtil.formatRelative(new Date().getTime() - (60 * 1000 * 60 * 3), SimpleDateFormat.getDateTimeInstance()));
long t = new Date().getTime() - (60 * 1000 * 60 * 100);
assertEquals(SimpleDateFormat.getDateTimeInstance().format(t), StringUtil.formatRelative(t, SimpleDateFormat.getDateTimeInstance()));
}
}