0

Is possible to set the system time (using Win32SetSystemTime) without changing hour, minute and second (only year, month and day)?

Here is my code. As you can see, I commented falseData.Hour, falseData.Minute and falseData.Second because I don't want to change them. With this code, however, system time is automatically setted on 01:00:00. Manually, I can change the system date without changing hour, minute and second (by clicking the clock of the taskbar), but programmatically?

Any help will be appreciated. Thanks. Marco

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Globalization; 
using System.Runtime.InteropServices; 

namespace SysData1_0
{
    public partial class Form1 : Form
    {
        public struct SystemTime
        {
            public ushort Year;
            public ushort Month;
            public ushort DayOfWeek;
            public ushort Day;
            public ushort Hour;
            public ushort Minute;
            public ushort Second;
            public ushort Milliseconds;
        };

        [DllImport("kernel32.dll", EntryPoint = "GetSystemTime", SetLastError = true)]
        public extern static void Win32GetSystemTime(ref SystemTime sysTime);

        [DllImport("kernel32.dll", EntryPoint ="SetSystemTime",SetLastError=true)]
        public extern static bool Win32SetSystemTime(ref SystemTime sysTime);

        public Form1()
        {
            InitializeComponent();
        }   

        private void buttonImpostaDataFittizia_Click(object sender, EventArgs e)
        {
            SystemTime falseData = new SystemTime ();
            if (comboBox.SelectedIndex == 0)
            {
                falseData.Year = (ushort)2015;
                falseData.Month = (ushort)3;
            }

            if (comboBox.SelectedIndex == 1)
            {
                falseData.Year = (ushort)2014;
                falseData.Month = (ushort)9;
            }

            //Please, read here 
            falseData.Day = (ushort)1;
            //falseData.Hour = (ushort)10 - 1;
            //falseData.Minute = (ushort)30;
            //falseData.Second = (ushort)30;
            Win32SetSystemTime(ref falseData);

            string Y,M,D;
            Y = Convert.ToString(falseData.Year);
            M = Convert.ToString(falseData.Month);
            D = Convert.ToString(falseData.Day);
            textBoxDataImpostata.Text = D + "/" + M + "/" + Y;
        }
    }
}
Guy
  • 1,434
  • 1
  • 19
  • 33
  • 1
    Note that in general users can't change time. From the SetSystemTime page: `The calling process must have the SE_SYSTEMTIME_NAME privilege.` – xanatos Mar 18 '15 at 12:38
  • 1
    As another sidenote, in general reading and then setting the time in this way could be dangerous... Let's say that between the GetSystemTime and the SetSystemTime the user hibernates his pc for 1h and then reactivates it 1h later :-) – xanatos Mar 18 '15 at 12:39
  • I agree with @xanatos here, you can do it, but I'm not sure you should. I don't know what you want to achieve though. – Falanwe Mar 18 '15 at 12:52
  • @xanatos and Falanwe: thank you for your comments. However, I will execute the application only on my own computer, as administrator. Hence, no risks here... – GMarco1989 Mar 19 '15 at 20:27

2 Answers2

1

Actually, that's pretty easy to do, and you already have all the methods you need. Just get the current time before modifying it and injecting it back to the system:

var nowSystemTime = new SystemTime(); //dummy value so that the code compiles.

Win32GetSystemTime(ref nowSystemTime);

nowSystemTime.Year = (ushort)2015;
nowSystemTime.Month = (ushort)3;

Win32SetSystemTime(ref nowSystemTime);

Of course, if you go this way, make sure you don't spend to much time before injecting the system time back, or find a way to compensate!

Falanwe
  • 4,636
  • 22
  • 37
  • There is no return value for `Win32GetSystemTime`, so no `if` is necessary. The sentence `//dummy value so that the code compiles.` is wrong. You create the `nowSystemTime` because `GetSystemTime` needs a reference to a "place" where to put the system time. – xanatos Mar 18 '15 at 12:36
  • @xanatos : you're right about the `if`, I misread the signature, confusing it with the `Win32SetSystemTime` one. However, the commentary IS right. semantically, `Win32GetSystemTime` should not take a `ref`parameter because it doesn't use the value of the reference provided, and it sets its value. Semantically it should be an `out`parameter. So I have to initialize my variable just so the code compiles. If C# accepted uninitialized variables in that case (as it does with `out` parameters), the code would run just fine. So the constructor is just here to appease the compiler. – Falanwe Mar 18 '15 at 12:42
  • Yes, the signature could be changed to `out` and then it would be correct. – xanatos Mar 18 '15 at 12:46
  • @xanatos: to be a little more specific, `GetSystemTime` DOES need a 'place' to put its return, but it's not the constructor that creates this location, it's the variable declaration. Having an `out` parameter would be perfect, but I'm not sure it's possible when doing marshalling. – Falanwe Mar 18 '15 at 12:50
  • I know... It feels only a little "unclean"... Mentally I do know how it works (and why it works)... But it still gives me a little shiver :) (and then it is a little nitpick that would be lost to 90% of the programmers, that then would ask "why"/"how") – xanatos Mar 18 '15 at 12:55
  • @Falanwe: I already thought your solution, but even if I'm fast on changing the time, this will be always old...A way to compensate could be connect the application to a time.windows server, but in this case an internet connection is necessary and I don't want this. – GMarco1989 Mar 19 '15 at 20:40
0

All SystemTime fields are initialized to their type's default value at creation : 0 for ushort.

You actually set the date related values, but not the time related ones, which stay at 0.

I guess the 1 in hours is related to your time zone.

You should do something like :

falseData.Hour = DateTime.Now.Hour
falseData.Minute = DateTime.Now.Minute
falseData.Second = DateTime.Now.Seconds
IronSlug
  • 492
  • 3
  • 15
  • thanks for your comment. This way seems to be good. I have modified the code a bit: `public int Hour; ` `public int Minute;` `public int Second;` `falseData.Hour = DateTime.UtcNow.Hour` `falseData.Minute = DateTime.UtcNow.Minute` `falseData.Second = DateTime.UtcNow.Seconds` Now hour is not modified, but there is something strange: minute is setted on 00 (default value) and second is setted exaclty as the minute before running the application. [...] – GMarco1989 Mar 19 '15 at 21:58
  • [...] For example, system time before running the application is 22:34:17; after running it, system time is setted on 22:00:34. It's strange... p.s. you are right, -1 was related to my time zone. Thanks. – GMarco1989 Mar 19 '15 at 22:04